Serializing the ClaimsIdentity

You aren't here

We’re doing a lot of WIF/Identity work at the moment, and we needed to look for a good way to serialise the ClaimsIdentity (so that we could pass it nicely around between tiers).

We ended up looking at the JwtSecurityTokenHandler, (short for JSON Web Tokens) which was built exactly for this.  The JwtSecurityTokenHandler not only allows you to serialise the ClaimsIdentity, but also allows you to secure and verify the token.

We implemented this through some simple extension methods, and opted to secure the token with an X509 cert. We already have the certificate installed on all of our servers, making it a simple candidate to use.

The Implementation:

Token Generation (dehydration, on the sender):

public static string GenerateToken(this ClaimsIdentity identity, X509Certificate2 certificate)
{
	var now = DateTime.UtcNow;
	var tokenHandler = new JwtSecurityTokenHandler();
	var tokenDescriptor = new SecurityTokenDescriptor
	{
		Subject = identity,
		TokenIssuerName = "self",
		AppliesToAddress = "http://www.mycompany.com",
		Lifetime = new Lifetime(now, now.AddMinutes(5)),
		SigningCredentials = new X509SigningCredentials(certificate)
	};
 
	var token = tokenHandler.CreateToken(tokenDescriptor);
	var tokenString = tokenHandler.WriteToken(token);
 
	return tokenString;
}

Token Rehydration (on the receiver):

public static ClaimsIdentity ReadToken(this string token, X509Certificate2 certificate)
{
	var tokenHandler = new JwtSecurityTokenHandler();
	var x509SecurityToken = new X509SecurityToken(certificate);
	var validationParameters = new TokenValidationParameters()
	{
		ValidAudience = "http://www.mycompany.com",
		IssuerSigningToken = x509SecurityToken,
		ValidIssuer = "self",
	};
 
	var validatedToken = new JwtSecurityToken() as SecurityToken;
	var claimsPrincipal = tokenHandler.ValidateToken(token, validationParameters, out validatedToken);
 
	return claimsPrincipal.Identity as ClaimsIdentity;
}

And a simple, easy helper function to find our certificate for us:

public static X509Certificate2 FindCertificate(string certificateName, StoreName storeName = StoreName.My, StoreLocation storeLocation = StoreLocation.LocalMachine)
{
	var store = new X509Store(storeName, storeLocation);
	store.Open(OpenFlags.ReadOnly);
	var certs = store.Certificates.Find(X509FindType.FindBySubjectName, certificateName, false);
 
	if (certs.Count == 0)
		throw new InvalidSecurityException("IdentityExtensions: Could not find X509 Certificate in store");
 
	return certs[0];
}

Image Credit: JD Hancock

Leave a Reply

Your email address will not be published. Required fields are marked *