Creating a JWT-Token in Windows 8.1 Phone App

I thought I quickly download the JWT nuget package to my Windows 8.1 universal app. Well I was wrong.  After some searching I found this article Creating a JWT token to access Windows Azure Mobile Services. But System.Security.Cryptography is no longer available in Windows Phone 8.1 Universal Apps. You should rather use the classes in Windows.Security.Cryptography which are of course inherently different.

So I rewrote the JsonWebToken Class to work in my universal app and share this here if you run into the same issue. I validated it with the JWT debugger on http://jwt.io/.

BTW, before you ask that question: “Why do you not use Windows 10 Universal App?” Answer: I would if the Windows 10 Preview on my Windows Phone would be in a better shape Smile. This was the first preview I had to roll back in my life.

/// <summary>
/// based on http://www.contentmaster.com/azure/creating-a-jwt-token-to-access-windows-azure-mobile-services
/// Reimplemented cryptographic part
/// </summary>
public class JsonWebToken
{
/// <summary>
/// Create a HMACSHA256 Signing HASH
/// </summary>
/// <param name="signingKey"></param>
/// <param name="bytesToSign"></param>
/// <returns></returns>
private static byte[] HMACSHA256(byte[] signingKey, byte[] bytesToSign)
{
var signingKeyBuffer = CryptographicBuffer.CreateFromByteArray(signingKey);
var bytesToSignBuffer = CryptographicBuffer.CreateFromByteArray(bytesToSign);

var hmacAlgorithm = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256);
var hash = hmacAlgorithm.CreateHash(signingKeyBuffer);
hash.Append(bytesToSignBuffer);
string base64Hash = CryptographicBuffer.EncodeToBase64String(hash.GetValueAndReset());
return Convert.FromBase64String(base64Hash);
}

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);
byte[] signature = HMACSHA256(keyBytes, 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;
}

internal static string TestJWT()
{
var privateKey = "secret";
var issueTime = DateTime.Now;
var utc0 = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var exp = (int)issueTime.AddMinutes(60).Subtract(utc0).TotalSeconds;
var payload = new
{
exp = exp,
ver = 1,
aud = "[Your AUD]",
uid = "[A unique identifier for the authenticated user]"
};
return JsonWebToken.Encode(payload, privateKey);
}
}

Enjoy your day

AndiP