I am trying to understand how to verify signatures of JWT tokens using the .NET Framework. I am using the token found at https://jwt.io/ .
If I understand how this is supposed to work, I can use the HMACSHA256 hashing algorithm with the first two tokens and a secret value to get the last part of the token. If that matches, then the signature is valid.
The example on the https://jwt.io/ page shows computing the hash in the following way:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload), secret
)
Unfortunately the HMACSHA256 object in the .NET Framework has no such method. You must pass in a byte[] or a stream. There is no argument for secret either. There is, however a constructor that takes in a byte[] as a key. In order to work around, I have been converting the word "secret" to a byte[] instantiating the HMACSHA256 object with that.
I then convert the base64 encoded header.payload string to a byte[] and pass that to the ComputeHash
method of the HMACSHA256
object.
Here is where I run into problems. The output from ComputeHash
is a byte array. No matter how I try converting this byte[] back to a string, it never matches the signature. I don't understand where I am going wrong. Is the signature portion of the token a hash value or a base64 encoded hash value?
Here is my code:
string jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ";
string[] parts = jwt.Split(".".ToCharArray());
string headerDotPayload = string.Format("{0}.{1}", parts[0], parts[1]);
string signature = parts[2];
byte[] secret = System.Text.UTF8Encoding.UTF8.GetBytes("secret");
byte[] input = System.Text.UTF8Encoding.UTF8.GetBytes(headerDotPayload);
var alg = new HMACSHA256(secret);
byte[] hash = alg.ComputeHash(input);
//Attempting to verify
StringBuilder result = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
result.Append(hash[i].ToString("x2"));
}
string verify1 = result.ToString(); //Does not match signature
string verify2 = System.Text.UTF8Encoding.UTF8.GetString(hash); //Does not match signature
byte[] verify3 = System.Text.UTF8Encoding.UTF8.GetBytes(signature); //Does not match value in the hash byte[]