I'm trying to create a JWT token that I can use to authenticate with Windows Azure Mobile Services.
If I use the following Node.js code to create the signature, it works when I make a request to WAMS:
function zumoJwt(expiryDate, aud, userId, masterKey) { var crypto = require('crypto'); function base64(input) { return new Buffer(input, 'utf8').toString('base64'); } function urlFriendly(b64) { return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, ''); } function signature(input) { var key = crypto.createHash('sha256').update(masterKey + "JWTSig").digest('binary'); var str = crypto.createHmac('sha256', key).update(input).digest('base64'); return urlFriendly(str); } var s1 = '{"alg":"HS256","typ":"JWT","kid":0}'; var j2 = { "exp":expiryDate.valueOf() / 1000, "iss":"urn:microsoft:windows-azure:zumo", "ver":1, "aud":aud, "uid":userId }; var s2 = JSON.stringify(j2); var b1 = urlFriendly(base64(s1)); var b2 = urlFriendly(base64(s2)); var b3 = signature(b1 + "." + b2); return [b1,b2,b3].join("."); }
However, if I use the following C# code to create a token with the same payload, I get a message from WAMS saying: "Error: The authentication token's signature was malformed or signed by a different key."
public class JsonWebToken { public static string Encode(object payload, string key) { return Encode(payload, Encoding.UTF8.GetBytes(key)); } public static string Encode(object payload, byte[] keyBytes) { var segments = new List<string>(); var header = new { alg = "HS256", typ = "JWT", kid = 0 }; byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None)); byte[] payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload, Formatting.None)); segments.Add(Base64UrlEncode(headerBytes)); segments.Add(Base64UrlEncode(payloadBytes)); var stringToSign = string.Join(".", segments.ToArray()); var bytesToSign = Encoding.UTF8.GetBytes(stringToSign); var sha = new HMACSHA256(keyBytes); byte[] signature = sha.ComputeHash(bytesToSign); segments.Add(Base64UrlEncode(signature)); return string.Join(".", segments.ToArray()); } // from JWT spec private static string Base64UrlEncode(byte[] input) { var output = Convert.ToBase64String(input); output = output.Split('=')[0]; // Remove any trailing '='s output = output.Replace('+', '-'); // 62nd char of encoding output = output.Replace('/', '_'); // 63rd char of encoding return output; } }
Note: When I use the C# code, I am making sure that I append "JWTSig" to the key as happens in the JavaScript.
Note: I've run a test using exactly the same payload in both C# and JavaScript, ensuring that the first two segments of JWT token are the same in both languages. The third segment containing the signature differs in the two languages.
For example, from JavaScript I generate:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6MH0.eyJleHAiOjEzNzY3MTUwNjQuMDQ1LCJpc3MiOiJ1cm46bWljcm9zb2Z0OndpbmRvd3MtYXp1cmU6enVtbyIsInZlciI6MSwiYXVkIjoiaHR0cDovL2RyYm1vYnNlcnZsaXZlLm9ubWljcm9zb2Z0LmNvbS95b3VyYXBwIiwidWlkIjoidGhpc2lzdG90YWxseXVuaXF1ZSJ9.6DL-2J9Rb203tMrY3jmm_E3xl_YS5jtkVCmC2QsFeyU
And from C# I generate:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6MH0.eyJleHAiOjEzNzY3MTUwNjQuMDQ1LCJpc3MiOiJ1cm46bWljcm9zb2Z0OndpbmRvd3MtYXp1cmU6enVtbyIsInZlciI6MSwiYXVkIjoiaHR0cDovL2RyYm1vYnNlcnZsaXZlLm9ubWljcm9zb2Z0LmNvbS95b3VyYXBwIiwidWlkIjoidGhpc2lzdG90YWxseXVuaXF1ZSJ9.nOV1wSVRLXY-94_63_yut9oPK3GVzasKk9J8fcJipOw
So how do I create a signature for a JWT using C# that will work with WAMS?
Thanks,
D