简体   繁体   中英

JSON Web Tokens Not Decodable on jwt.io: “JWT payload is not a valid JSON object”

Using the below code, I am able to build a decoded JSON Web Token ( decodedToken ). When I paste it into the debugger on https://jwt.io , the header and payload are correctly shown on the right. But when I paste the encoded token ( encodedToken ) into the debugger, I get this message:

Looks like your JWT payload is not a valid JSON object. JWT payloads must be top level JSON objects as per https://tools.ietf.org/html/rfc7519#section-7.2

It also says, "Invalid Signature," in big red letters at the bottom.

In addition, when using the encoded token, the header area shows my decoded header, and the payload area shows my entire decoded token . So somehow jwt.io is successfully decoding the JWT. But it shouldn't be trying to parse the JSON of the entire decoded token as a single unit. It should be trying to parse the JSON of the header and payload portions separately.

I would like to know why jwt.io can't quite my payload of my encoded token. The values of both the decodedToken and encodedToken are shown as comments in the below source code. Thank you.

private static string GetEncodedToken(string privateKey)
{
    JObject header = JObject.FromObject(new { alg = "ES384", typ = "JWT" });
    JObject payload = JObject.FromObject(new { name = "value" });//simple test JSON data
    string decodedToken = Base64URLEncode(header) + "." + Base64URLEncode(payload);
    //eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidmFsdWUifQ
    byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
    using (ECDsa ecdsa = ECDsa.Create())
    {
        ecdsa.ImportECPrivateKey(privateKeyBytes, out _);
        string encodedToken = JWT.Encode(decodedToken, ecdsa, JwsAlgorithm.ES384);
        //eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.ZXlKaGJHY2lPaUpGVXpNNE5DSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnVZVzFsSWpvaWRtRnNkV1VpZlE.kYj0M2GNC5w9oRrIVcHJ9dSQLbOEjNjxd61zSXD5iz0nBRRWMWyxj2l1DAhKPa_hpaFUscuubCzYe_W1SKpo3s06on-hYnICgQH4fVoAwZxiM_N4W761jecOExfivztn
        return encodedToken;
    }
}

private static string Base64URLEncode(JObject jObject)
{
    string jsonString = jObject.ToString(Formatting.None);
    byte[] jsonBytes = Encoding.UTF8.GetBytes(jsonString);
    string escapedBase64 = Convert.ToBase64String(jsonBytes).TrimEnd('=').Replace('+', '-').Replace('/', '_');
    return escapedBase64;
}

Update

Thank you for the answers so far. I think I'm close, but jwt.io still says, "Invalid Signature," even though I've pasted in the public key. Using the below information, I'm hoping someone can tell me why my signature is said to be invalid.

I've generated a temporary private key just for the purpose of debugging this situation on stackoverflow.com: MIGkAgEBBDBywQ7LVcyOGzxJ0Tpjpww2zUZbbtb3WVm4A3uv7ho31jJzQRYTpSqR7+ORAdoxmamgBwYFK4EEACKhZANiAASG50vW1r/O1XmUbTBb6yx1YSABh1USA6MJ8HJnYJ58tjGGVPL88a6Z1gOUlAsHtNhL44PhnTNTNNFdaH2Z41yn7oZmBhuon0vuUNFic2HDpfa/uFwRUAmhSBQz8hu+980=

I initialized an instance of ecdsa with my private key and generated a public key with Convert.ToBase64String(ecdsa.ExportSubjectPublicKeyInfo()) : MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEhudL1ta/ztV5lG0wW+ssdWEgAYdVEgOjCfByZ2CefLYxhlTy/PGumdYDlJQLB7TYS+OD4Z0zUzTRXWh9meNcp+6GZgYbqJ9L7lDRYnNhw6X2v7hcEVAJoUgUM/IbvvfN

Here is the updated code:

private static string GetSignedEncodedToken(string privateKey)
{
    JObject payload = JObject.FromObject(new { name = "value" });//simple test JSON data
    string payloadString = payload.ToString(Formatting.None);
    byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
    using (ECDsa ecdsa = ECDsa.Create())
    {
        ecdsa.ImportECPrivateKey(privateKeyBytes, out _);
        string signedEncodedToken = JWT.Encode(payloadString, ecdsa, JwsAlgorithm.ES384);
        return signedEncodedToken;
    }
}

And here is the signed encoded token: eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.ew0KICAibmFtZSI6ICJ2YWx1ZSINCn0.KpJAgc3-yaoGmHGAXHOeH3BPgpxdBRm461yWia60dgjuQHG5iLnwLQtQgdZtsHnI-bEK_wdmvu85ZrF7n-TdWiFb4FQxGeLBeeRfnMLJhKfInu_7MYEWPS2Ohm4yBAqg

Solution to Update

As mentioned by jps, I needed to wrap my public key with "-----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----". Then jwt.io shows, "Signature Verified."

What you're calling decodedToken here is basically already an encoded token without signature. The function JWT.Encode takes the first parameter and repeats what you already did manually, ie it creates a base64url encoded header and payload for you and then signs the token. You don't need to create your own header and you don't need to care about base64url encoding.

Therefore you just need to pass your payload (not base64 encoded) there. The result is a signed token.

And jwt.io shows "invalid signature" because you probably didn't pass the public key to the "public key" field in the right column. Without knowing the public key, the signature can't be verified.

When you paste a public key there, make sure it has the header and footer lines -----BEGIN PUBLIC KEY----- -----END PUBLIC KEY----- , then verification should work fine.

Token that you have provided, I used the same in jwt.io debugger and can see couple of issues:

eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.ZXlKaGJHY2lPaUpGVXpNNE5DSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnVZVzFsSWpvaWRtRnNkV1VpZlE.kYj0M2GNC5w9oRrIVcHJ9dSQLbOEjNjxd61zSXD5iz0nBRRWMWyxj2l1DAhKPa_hpaFUscuubCzYe_W1SKpo3s06on-hYnICgQH4fVoAwZxiM_N4W761jecOExfivztn

Following are decoded details:

Header (which is correct):

{
  "alg": "ES384",
  "typ": "JWT"
}

Payload (which is not correct):

"eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidmFsdWUifQ"

Since Payload is expected to be Json, not a Base64Encoded string. You shall be able to modify it to generate a new Token.

Now Main Error:

For decoding debugger surely needs Public Key, which can match with Private Key, that's in case you use Asymmetric encryption, in case you use Symmetric encryption then both keys will be same.

Optionally you can also add the Private Key to generate the new token with modified algorithm or payload.

Programmatically you are able to see the details:

  1. You are supplying the right Public key to match the Private Key
  2. You convert Base64String to Json programmatically. which is not feasible for JWT debugger

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM