Maybe you have read my previous blog post in which I talked about token generation in OWIN. After the issues we had there with Machine key and OWIN versions, I decided to take a look at some alternatives.
After some research I decided JSON Web Tokens (or JWT’s, which apparently should be pronounced as the English word ‘jot’) would fit the bill. They are small, it is an open standard, and has a simple string representation (URL-safe). More info on the standard can be found in this draft.
After this research it should be a easy to incorporate this into my solution right? Well… not as easy as I thought. It turns out many samples are just using an external STS to create and verify tokens, or using some own custom implementation which doesn’t support all of the options. Let alone complete samples of generating a token in a WCF service and using it in a client to pass on to another service. However after a lot of searching, researching etc. I decided to make my own sample.
So here comes the first part, generating and consuming:
I will be using the “JSON Web Token Handler for the Microsoft .NET Framework 4.5” NuGet Package as it is called by its full name. It is also called System.IdentityModel.Tokens.Jwt. So in this post I’ll just show you how to create a token from some claims and then how to turn the token back into claims again. Just in a console application so we can more easily see what is going on.
I have just created a new Console application in Visual Studio 2015, and added the aforementioned NuGet package. At the time of writing the latest stable version is 4.0.2.206221351. Don’t forget to add a reference to the System.IdentityModel assembly as well, it is part of the .NET Framework since v4.5.
First we will add some using clauses we will need:
using System.IdentityModel.Tokens;
using System.Security.Claims;
Before we can sign a token we need a secret to sign it with. There a multiple options like certificates and whatnot. The easiest to use in this example however is just a normal shared secret text. Which we will need to turn into a byte array before we can make it a secret key. Also we will have to put it in a SigningCredentials object together with the algorithms we will use to sign it with:
var plainTextSecurityKey = "This is my shared, not so secret, secret!";
var signingKey = new InMemorySymmetricSecurityKey(
Encoding.UTF8.GetBytes(plainTextSecurityKey));
var signingCredentials = new SigningCredentials(signingKey,
SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.Sha256Digest);
You can use a couple of different security algorithms but you should specify one which ends in signature for the first one, and one that ends in digest for the second algorithm. Some will throw a NotSupportedException (because, not supported) and HmacSha256Signature and Sha256Digest seem to be the default in most examples I have seen.
After that we will need a few claims to put in the token, otherwise why would we need a token:
var claimsIdentity = new ClaimsIdentity(new List<Claim>()
{
new Claim(ClaimTypes.NameIdentifier, "myemail@myprovider.com"),
new Claim(ClaimTypes.Role, "Administrator"),
}, "Custom");
Now we can create the security token descriptor:
var securityTokenDescriptor = new SecurityTokenDescriptor()
{
AppliesToAddress = "http://my.website.com",
TokenIssuerName = "http://my.tokenissuer.com",
Subject = claimsIdentity,
SigningCredentials = signingCredentials,
};
Please note that the AppliesToAddress and TokenIssuerName must be valid URI’s. Not in the sense that they should be resolvable, but they must be in a valid URI format (if you have accidentally read the v3.5 WIF documentation this can be confusing, it says that any string will do). The AppliesToAddress should contain the token’s audience, which means the website or application that will receive te token. The TokenIssuerName is the application issuing the token obviously.
This token descriptor can now be used with any WIF (Windows Identity Foundation) token handler (see the SecurityTokenHander class MSDN help). The JwtSecurityTokenHandler we are going to use is a descendant from that class (and implements the necessary abstract members).
Here is the code to create a token, then sign and encode it:
var tokenHandler = new JwtSecurityTokenHandler();
var plainToken = tokenHandler.CreateToken(securityTokenDescriptor);
var signedAndEncodedToken = tokenHandler.WriteToken(plainToken);
If you want you can print the stuff on the screen now to see what it generated:
Console.WriteLine(plainToken.ToString());
Console.WriteLine(signedAndEncodedToken);
Console.ReadLine();
Now that we have the encoded token that is easily transportable we might want some other application to validate the token (to see that it was not tampered with). To do this, we first need an instance of the TokenValidationParameters class:
var tokenValidationParameters = new TokenValidationParameters()
{
ValidAudiences = new string[]
{
"http://my.website.com",
"http://my.otherwebsite.com"
},
ValidIssuers = new string[]
{
"http://my.tokenissuer.com",
"http://my.othertokenissuer.com"
},
IssuerSigningKey = signingKey
};
As you can see, the TokenValidationParameters class allows us to specify multiple valid issuers and audiences. You will also need to specify the same signing key as when you created the token (obviously). We can now simply validate the token the following way:
SecurityToken validatedToken;
tokenHandler.ValidateToken(signedAndEncodedToken,
tokenValidationParameters, out validatedToken);
Console.WriteLine(validatedToken.ToString());
Console.ReadLine();
You might be wondering how the token handler knows which signature and digest algorithms should be used. However if you look carefully you will see that the algorithm name is encoded into the token (this encoding is simply Base64, not encrypted).
The source code to this sample can be found here.