How do I create a signature for a JWT token for use with Windows Azure Mobile Services

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

August 16th, 2013 1:47pm

hi Betts,

--------------------------------------------------

For example, from JavaScript I generate:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6MH0.eyJleHAiOjEzNzY3MTUwNjQuMDQ1LCJpc3MiOiJ1cm46bWljcm9zb2Z0OndpbmRvd3MtYXp1cmU6enVtbyIsInZlciI6MSwiYXVkIjoiaHR0cDovL2RyYm1vYnNlcnZsaXZlLm9ubWljcm9zb2Z0LmNvbS95b3VyYXBwIiwidWlkIjoidGhpc2lzdG90YWxseXVuaXF1ZSJ9.6DL-2J9Rb203tMrY3jmm_E3xl_YS5jtkVCmC2QsFeyU

And from C# I generate:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6MH0.eyJleHAiOjEzNzY3MTUwNjQuMDQ1LCJpc3MiOiJ1cm46bWljcm9zb2Z0OndpbmRvd3MtYXp1cmU6enVtbyIsInZlciI6MSwiYXVkIjoiaHR0cDovL2RyYm1vYnNlcnZsaXZlLm9ubWljcm9zb2Z0LmNvbS95b3VyYXBwIiwidWlkIjoidGhpc2lzdG90YWxseXVuaXF1ZSJ9.nOV1wSVRLXY-94_63_yut9oPK3GVzasKk9J8fcJipOw

------------------------------------------------------

Form this generated string,I think your js code and c# code may have some problem.

I pay attention to your code,I think the question may be about this(I didnt try your code):

  return string.Join(".", segments.ToArray());

Join method is joind the element in the array.So the secondly param may be a array type.

So i suggestion you can change this

return string.Join(".", segments);
you can try it
Free Windows Admin Tool Kit Click here and download it now
August 17th, 2013 1:14pm

I'm not familiar with Node.js. But try to do one thing at a time. Since the first two sigments are the same, you can focus on the third sigment, the sign. Compare the output of the following:

var str = crypto.createHmac('sha256', key).update(input);

byte[] signature = sha.ComputeHash(bytesToSign);

That is, compute the HMAC without base64 encoding. If the results are different, then the problem lies in how you compute HMAC. For example, maybe the keys are different (you mentioned you have "JWTSig" in the C# version but I can't see it in the code). If the results are the same, then check remainint steps, such as base64 computing and URL encoding.

By the way, you can use .NET's built-in UrlEncode method: http://msdn.microsoft.com/en-us/library/system.web.httputility.urlencode.aspx

August 18th, 2013 10:33am

I've looked a bit more closely at exactly what the Node.js JavaScript code is doing and determined that the C# code is (not surprisingly) not doing the same.

The Node.js code uses a hash of the master key to generate the signature, whereas the C# code uses the master key directly when it generates the signature.

The relevant bit of C# code should be:

SHA256Managed hash = new SHA256Managed();
byte[] signingBytes = hash.ComputeHash(keyBytes);

var sha = new HMACSHA256(signingBytes);
byte[] signature = sha.ComputeHash(bytesToSign);

Using this code, I can create a JWT token that's accepted by WAMS.

- Dominic

Free Windows Admin Tool Kit Click here and download it now
August 19th, 2013 8:54am

is it still working?

i'm new on azure developing, and i want a custom api without google/fb/etc... so i'm trying to generate by myself jwt like you... (working with c# backend and testing on windows store c# app easy to learn/develop/test...)

first test was with facebook auth (keys configured on azure portal...), i received id/token, saved and reused and server auth works... ok...

then testing selfmade jwt i receive an excpetion on client while "packing" request suppose,  in Newtonsoft.Json.Linq on  public static JToken Parse(string json) because it tries to parse a json string==""...

the first thing that i've noted is that in jwd, the second section in very much shorter with nodejs/c# custom version compared to "official" fb one.

is this difference normal?could you help me to understand and make it working? thanks

March 28th, 2014 9:36am

Check out https://github.com/juanfranblanco/ZumoSharp it is an implementation of JWT and authentication in C#

Free Windows Admin Tool Kit Click here and download it now
March 4th, 2015 1:59pm

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics