Web API Authentication Using JWT Token

JWT - (JSON Web Token)

JWT basically consists of three parts.

  • HEADER : ALGORITHM & TOKEN TYPE (JSON format which is encoded as a base64)
  • PAYLOAD : DATA (JSON format which is encoded as a base64.)
  • VERIFY SIGNATURE (Created and signed based on Header and Claims which is encoded as a base64.)

We use JWT just to verify that the request coming to our API is from a valid source. The above mentioned three parts are separated using dot (.) respectively in the encoded form.

It is basically used to encode our data using the algorithms we apply. JWT is very lightweight and can encode large amount of sensitive data which can even be passed as a query string.

Creation of JWT

  • Use the NuGet package called System.IdentityModel.Tokens.Jwt from MS to generate the token.
  • Validate for correct user from database and if validated, then generate the token by putting its information in payload and return that token to that user.
  • Add .cs file and write the below method to generate token.
    1. private  
    2. const string Secret = "db3OIsj+BXE9NZDy0t8W3TcNekrF+2d/1sFnWG4HnV8TZY30iTOdtVWJG8abWvB1GlOgJuQZdcF2Luqm/hccMw==";  
    3. public static string GenerateToken(string username, int expireMinutes = 20) {  
    4.     var symmetricKey = Convert.FromBase64String(Secret);  
    5.     var tokenHandler = new JwtSecurityTokenHandler();  
    6.     var now = DateTime.UtcNow;  
    7.     var tokenDescriptor = new SecurityTokenDescriptor {  
    8.         Subject = new ClaimsIdentity(new [] {  
    9.                 new Claim(ClaimTypes.Name, username)  
    10.             }),  
    11.             Expires = now.AddMinutes(Convert.ToInt32(expireMinutes)),  
    12.             SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(symmetricKey), SecurityAlgorithms.HmacSha256Signature)  
    13.     };  
    14.     var stoken = tokenHandler.CreateToken(tokenDescriptor);  
    15.     var token = tokenHandler.WriteToken(stoken);  
    16.     return token;  
    17. }  
  • The user will save the returned token either in session or local storage or in cookies, because for every new request, it will have to attach that token with request in header so that it can be validated with every new request. Thus, in this way, the API ensures that the incoming request is from a valid user.

Consumption of JWT

Add AuthorizationAttribute in WebApiConfigFile.

Eg

config.Filters.Add(new AuthorizeAttribute());

built JwtAuthenticationAttribute which inherits from IauthenticationFilter. With this attribute, you can authenticate any action. Just put this attribute on that action.

  1. public class ValueController: ApiController {  
  2.     [JwtAuthentication]  
  3.     public string Get() {  
  4.         return "value";  
  5.     }  
  6. }  

Below is the core method from authentication filter.

  1. private static bool ValidateToken(string token, out string username) {  
  2.     username = null;  
  3.     var simplePrinciple = JwtManager.GetPrincipal(token);  
  4.     var identity = simplePrinciple.Identity as ClaimsIdentity;  
  5.     if (identity == nullreturn false;  
  6.     if (!identity.IsAuthenticated) return false;  
  7.     var usernameClaim = identity.FindFirst(ClaimTypes.Name);  
  8.     username = usernameClaim ? .Value;  
  9.     if (string.IsNullOrEmpty(username)) return false;  
  10.     // More validate to check whether username exists in system  
  11.     return true;  
  12. }  
  13. protected Task < IPrincipal > AuthenticateJwtToken(string token) {  
  14.     string username;  
  15.     if (ValidateToken(token, out username)) {  
  16.         // based on username to get more information from database in order to build local identity  
  17.         var claims = new List < Claim > {  
  18.             new Claim(ClaimTypes.Name, username)  
  19.             // Add more claims if needed: Roles, ...  
  20.         };  
  21.         var identity = new ClaimsIdentity(claims, "Jwt");  
  22.         IPrincipal user = new ClaimsPrincipal(identity);  
  23.         return Task.FromResult(user);  
  24.     }  
  25.     return Task.FromResult < IPrincipal > (null);  
  26. }  

The workflow is using JWT library (NuGet package above) to validate the JWT token and then return back ClaimsPrincipal. We can perform more validation like checking whether user exists on our system and adding other custom validations if we want. The code is to validate JWT token and get principal back.

  1. public static ClaimsPrincipal GetPrincipal(string token) {  
  2.     try {  
  3.         var tokenHandler = new JwtSecurityTokenHandler();  
  4.         var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;  
  5.         if (jwtToken == nullreturn null;  
  6.         var symmetricKey = Convert.FromBase64String(Secret);  
  7.         var validationParameters = new TokenValidationParameters() {  
  8.             RequireExpirationTime = true,  
  9.                 ValidateIssuer = false,  
  10.                 ValidateAudience = false,  
  11.                 IssuerSigningKey = new SymmetricSecurityKey(symmetricKey)  
  12.         };  
  13.         SecurityToken securityToken;  
  14.         var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);  
  15.         return principal;  
  16.     } catch (Exception) {  
  17.         //should write log  
  18.         return null;  
  19.     }  
  20. }  

If the JWT token is validated and the principal is returned, you should build a new local identity and put more information into it to check the role authorization.

Ebook Download
View all
Learn
View all