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://www.rfc-editor.org/rfc/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."