JSON Web Token (JWT) Support in Thinktecture.IdentityModel

As noted in my last post, I added a simple implementation of JWT to Thinktecture.IdentityModel. It supports plaintext JWTs (unsigned) and symmetric signatures (HMACSHA 256, 384, 512). I haven’t implemented encryption or asymmetric signatures. For the latest specs see here.

Disclaimer: This is the very first public version, expect some bugs ;)

The implementation consists of a SecurityToken and SecurityTokenHandler derived class which completely integrated JWTs into .NETs/WIFs identity model and makes JWTs usable in ASP.NET (WS-Fed), WCF (WS-Trust) and HTTP (e.g. OAuth2 in Web API) scenarios. Here are some examples.

Manually creating a JWT
In this example, I simply create a JsonWebToken, set some properties and use the token handler to serialize it:

var jwt = new JsonWebToken

{

    Header = new JwtHeader

    {

        SignatureAlgorithm = JwtConstants.SignatureAlgorithms.HMACSHA256

        SigningCredentials = new HmacSigningCredentials(key),

    },

 

    Audience = new Uri(http://foo.com”),

    Issuer = “dominick”,

    ExpirationTime = 1355785200,

 

    Claims = new List<Claim>

    {

        new Claim(ClaimTypes.Name, “dominick”),

        new Claim(ClaimTypes.Email, “dominick.baier@thinktecture.com”)

    }

};

 

var handler = new JsonWebTokenHandler();

var tokenString = handler.WriteToken(jwt);

 

Reading a JWT and parsing it to a JsonWebToken is analogous. You just call ReadToken on the serialized string.

Using a SecurityTokenDescriptor to create a JWT
This method is used in security token services. With this support in place, you can simply add the token handler to your STS configuration, and your STS can emit JWTs.

var descriptor = new SecurityTokenDescriptor

{

    TokenIssuerName = “dominick”,

    AppliesToAddress = http://foo.com&#8221;,

    Lifetime = new Lifetime(DateTime.UtcNow, DateTime.UtcNow.AddHours(1)),

    SigningCredentials = new HmacSigningCredentials(key),

 

    Subject = new ClaimsIdentity(new Claim[]

        {

            new Claim(ClaimTypes.Name, “dominick”),

            new Claim(ClaimTypes.Email, “dominick.baier@thinktecture.com”)

        }, “JWT”)

};

 

var handler = new JsonWebTokenHandler();

var jwt = handler.CreateToken(descriptor);

 

Validating a JWT and creating a ClaimsIdentity
The ValidateToken method takes a JsonWebToken and turns it into claims. This (together with ReadToken method) is how you implement arbitrary relying parties, e.g. for OAuth.

This involves setting up a standard security token handler configuration options to specify:

  • trusted issuers (WebTokenIssuerNameRegistry)
  • signature verification key (WebTokenIssuerResolver)
  • audience validation

var config = new SecurityTokenHandlerConfiguration();

var registry = new WebTokenIssuerNameRegistry();

registry.AddTrustedIssuer(“dominick”, “dominick”);

 

config.IssuerNameRegistry = registry;

var issuerResolver = new WebTokenIssuerTokenResolver();

issuerResolver.AddSigningKey(“dominick”, Convert.ToBase64String(key));

config.IssuerTokenResolver = issuerResolver;

 

config.AudienceRestriction.AllowedAudienceUris.Add(new Uri(http://foo.com));

 

handler.Configuration = config;

ClaimsIdentity identity = handler.ValidateToken(jwt).First();

 

Have fun ;)

This entry was posted in IdentityModel, WebAPI. Bookmark the permalink.

44 Responses to JSON Web Token (JWT) Support in Thinktecture.IdentityModel

  1. Bob Gregory says:

    I’ve got a similar implementation at https://github.com/BobFromHuddle/Jwt4Net
    I’ve managed to get HMAC and ECC signing in, but I’ve never gotten around to RSA. I’d appreciate any feedback.

    – -B

    • Had a brief look. To properly integrate with WIF/.NET we need SecurityToken and SecurityTokenHandler derived classes. Should be doable. Have a look at my code to get a feeling what would be involved.

      I am on the road for 2 weeks now. After that I will have another look.

  2. bobfromhuddle says:

    I’ve got an implementation of ECC and RSA signing on https://github.com/bobfromhuddle/jwt4net
    Any feedback warmly received.
    The biggest problem I had was getting Crypto-next gen playing nicely with others. I’ve considered dropping that and moving to bouncy castle instead, but I find the API somewhat opaque.

  3. Joe Kaplan says:

    I’m definitely excited to see this and hope both of you can converge your design here. The RSA signing feature would be nice as I already have a fairly widely shared RSA key for my STS that I would like to be able to reuse but ECC sounds interesting as well. I’d be curious to find out if I can help as well.

  4. You can definitely help out ;) Let me find some time to go through the code….

  5. Joe Kaplan says:

    I didn’t yet install VS 2012 but I guess this is good motivation to do so. How does the JWT work intersect with IdSrv? Is there to be a .NET 4.5 version of it? I am also curious about what’s hard about RSA signing. I looked at Bob’s library a bit and it looks cool but it seems to not be aligned to WIF at all. What’s the overall concept there?

  6. I’ve run into two problems trying to read JWTs with the NuGet package for IndentityModel. The first is that I am only able to retrieve one value for a ClaimType (ie: I have multiple roles that show up in “My Roles” on the IdentityServer, but only one Role is read in the jwt token). The second problem is that I can only get 1 identity returned for a principal in the jwt. I forked the IdentityModel.45 repo so I could take a look at it and see if I could fix that, but I’m seeing conflicts between System.IdentityModel and Microsoft.IdentityModel. Should I create an issue on Github to track the development of these problems?

  7. Badri says:

    BTW, I have used HttpUtility.ParseQueryString() to parse the key value pairs of SWT and CSV list of roles is a by-product of using the same.

  8. Hans says:

    Hi Dominick,

    Is it possible to add an extra claim to the JWT if I use the IdentityModel? For instance I would like add an additional identificationnumber of the user to the token. When the user comes back with a new request, I want to use that number out of the token, combined with the issuername to get some data out of the database.

      • Hans says:

        Dominick,

        Ok I was hoping for that. I’m wondering around in the code for the last couple of days, looking at some great OO design en patterns. My goal is the create a MVC 4 website connecting to a Web API layer. The SimpleMembership provider is used to store the usercredentials and MVC andalso the Web API are both using the membership to validate the users.

        Using basic authentication on the Web API I can validate the user in the membership database and return a token (using SSL), so that not every call needs to have username and password in the header. I’ve got the POC up and running for the scenerio described, but where should I accomplish my feature to put an extra claim in the JWT token? In the AuthenticationConfig.cs I can set a ClaimsAuthenticationManager property. Should that be the way to go?

        I also checked the ConsultantsClaimsTransformer.cs and the custom httproute DefaultApiWithTransformation. I still however want to use the standard Thinktecture.IdentityModel.Tokens.Http.AuthenticationHandler. Can you give me some clues to get started?

        Thanks!

  9. Cool.

    So with JWT token, do you mean the built-in session token?

    Yeah – adding a claim is done in the ClaimsAuthenticationManager – set the property on AuthConfig and implement the class. This logic gets called after initial authentication and before the session token is issued.

  10. Hans says:

    Dominick,
    Maybe I’m missing something, but if I look at ClaimsAuthenticationManager class to implementate, there is an Authenticate function and I can use the CreateClientIdentity from the Consultant example to do some transformation. However that is in the proces of transforming an incoming ClaimsPrincipal. How can I add the additional claim to the token when it is been sent to to client for the first time?

  11. I am not sure I understand – when exactly do you want to add the claim. The typical place would be after authentication.

    • Hans says:

      The user authenticates for the first time on the Web API with basic authentication and gets a sessiontoken (like the JavaScriptClients example). In that sessiontoken I want to add some extra claims, that I can use the next time the user makes a call to the Web API with the token added in the header.

      • Right – And the principal you return from the claims auth manager is exactly what will get turned into the session token. So add your claim in there.

  12. Hans says:

    Ok, working on it!

    • Hans says:

      I got the implementation working. Thanks for your support. Now focussing on how to get the extra data/number in the membership database and getting it back in the Web API.

  13. Paul says:

    Hi Dominick, many thanks for the framework. I find it very helpful not only in leveraging WS-Trust, but also in learning it. Just one question: I notice that there are several classes that seem to be geared towards asymmetric signing in IdentityModel 4.5; do you have any idea when you’ll be supporting certificate-based encryption?

  14. Utsav Vishnoi says:

    Hi Dominick,

    I am manually creating a JWT Token using a ThinkTecture and i am facing this issue. Can you please suggest something to fix this.

    The token resolver is unable to resolve the security key reference ‘Thinktecture.IdentityModel.Tokens.WebTokenSecurityKeyClause’.

  15. Rakesh says:

    I mean IdentityModel

  16. Rakesh says:

    Ok thanks dominick. how to configure identity provider with thinktecture identity server.
    Is there any documentations for this.?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s