Can JSON Web Token (JWT) Be an Alternative for Session?

JSON Web Token (JWT) is nowadays commonly used for authentication, which is driven by IEFT OAuth Working Group. The current version of its draft is 32. Unlike other authentication tokens, JWT is a JSON object basically and encrypted as a string with delimiters.

JWT has been widely adapted for apps to send/receive RESTful API calls to web servers. For web applications, session objects are commonly used for authentication. Then, why not JWT? One of benefits using JWT as an authentication method, JWT is not server dependent, while session objects are. That means, if we use session objects for authentication, it will be quite tricky to handle between load-balanced web servers. JWT doesn’t necessarily rely on servers, on the other hand.

Here’s a sample code repository for JWT authentication with ASP.NET MVC.

Creating JWT

This requires JWT package, http://www.nuget.org/packages/System.IdentityModel.Tokens.Jwt, from NuGet.

var now = DateTime.UtcNow;
var tokenHandler = new JwtSecurityTokenHandler();
var symmetricKey = GetBytes("ThisIsAnImportantStringAndIHaveNoIdeaIfThisIsVerySecureOrNot!");
var tokenDescriptor = new SecurityTokenDescriptor
                          {
                            Subject = new ClaimsIdentity(new Claim[]
                                                             {
                                                               new Claim(ClaimTypes.Name, "DevKimchi"),
                                                               new Claim(ClaimTypes.Role, "User"),
                                                             }),
                            TokenIssuerName = "http://devkimchi.com",
                            AppliesToAddress = "http://jwt-sample.com",
                            Lifetime = new Lifetime(now, now.AddMinutes(30)),
                            SigningCredentials = new SigningCredentials(new InMemorySymmetricSecurityKey(symmetricKey),
                                                                        "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
                                                                        "http://www.w3.org/2001/04/xmlenc#sha256"),
                          };
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);

var cookie = new HttpCookie(".JWTAUTH", tokenString) { HttpOnly = true, };
`</pre>
  • symmetricKey: To encrypt authentication details.
  • tokenDescriptor: To create JSON token meeting all the requirements set by IETF. Basically, it contains login details, token issuing erver, token consuming location, token validation period and token encryption method. With these details, JWT is tokenised (token) and encrypted (tokenString).
  • cookie: To store the encrypted token.

    Additional Encryption with FormsAuthentication

    It is not necessary but to get more benefit from the FormsAuthentication object.

    ASP.NET MVC web apps use FormsAuthentication object to store auth details into a cookie. The cookie itself has already been encrypted and, when necessary, it’s decrypted at the server side. If we want to use this, the tokenString we created above can be stored into the cookie with following:

    `var ticket = new FormsAuthenticationTicket(
                     1,
                     model.Email,
                     now,
                     now.AddMinutes(30),
                     model.RememberMe,
                     tokenString,
                     FormsAuthentication.FormsCookiePath);
    
    var encryptedTicket = FormsAuthentication.Encrypt(ticket);
    var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket) { HttpOnly = true, };
    `
  • ticket: To create a ticket for FormsAuthentication. This ticket is encrypted and stored into encryptedTicket.

  • cooke: To store the encrypted ticket.

    Make sure that, FormsAuthentication object uses the machine key that is unique on each server. Therefore, if you want to use this approach between load-balanced servers, the machine key accross the all servers must be the same as each other.

    Authentication Verification at Global.asax

    When you see the ASP.NET HttpApplication lifecycle pipelines.aspx#remarksToggle), in global.asax, AuthenticationRequest can deal with the authentication check using the event handler, Application_AuthenticationRequest.

    `var jwtCookie = Request.Cookies[".JWTAUTH"];
    var userData = jwtCookie.Value;
    
    var tokenHandler = new JwtSecurityTokenHandler();
    var symmetricKey = GetBytes("ThisIsAnImportantStringAndIHaveNoIdeaIfThisIsVerySecureOrNot!");
    var validationParameters = new TokenValidationParameters()
                               {
                                 ValidAudience = "http://jwt-sample.com",
                                 ValidIssuer = "http://devkimchi.com",
                                 IssuerSigningToken = new BinarySecretSecurityToken(symmetricKey)
                               };
    SecurityToken securityToken;
    var principal = tokenHandler.ValidateToken(userData, validationParameters, out securityToken);
    
    Context.User = principal;
    `
  • symmetricKey: To decrypt auth details from JWT. This is the same key above.

  • validationParameters: To store keys and values to verify JWT. ValidAudience, ValidIssuer and IssuerSigningToken must be valid to be authenticated.
  • principal: To store user auth details from JWT.

    If FormsAuthentication object was used, we need to do something more beforehand:

    `var authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
    var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
    var userData = authTicket.UserData;

Conclusion

So far, we have a brief look at JWT for authentication. It doesn’t seem to be tricky but easy to setup. In addition to this, from the security perspective, authentication can be easily substitute sessions. Especially, one authentication approach can be used for all apps including web apps, desktop apps and mobile apps at one single endpoint. If your system needs to provide an integrated way of authentication, this could be an option.

Of course, DO NOT use this approach for authorisation. It should be considered separately.