Anjani Singh

JSON Web Token (JWT) with Web API

The modern approach for authenticating a user is through token based authentication scheme. It relies on signed tokens which are sent by user to server with each request. It is becoming very popular because it naturally blends with stateless Web APIs and other REST services.
Apart from being stateless, few other benefits of this approach are:
• Easy scalability
• Minimum need for managing server state
• Streamlined and decoupled authenticating services
• Protection against CSRF attacks

JWT with API

As evident, another reason for popularity of token based approach is the inherent support for distributed and cloud based infrastructure. Token based approach solves problem of traditional approach in which server has to store Ids of Session and relevant data for each individual. One of the token based approach is JSON-based Open Standard (RFC 7519) known as JSON Web Token. (JWT)

What is JWT?

JSON Web Token (JWT) is the approach of securely transmitting data across communication channel. For authentication and authorization, it uses the technique of passing digitally signed tokens. JWT comprises of three parts: Header, Payloads and Signature.
Header is used to identity the signing algorithm used and it appears like:

{ “alg”: “HS256”, “typ”: “JWT”}

Payload looks like:

{ “Name”: “Anjani singh”,”Admin”: “true”,”iat”: “146565644”}

The signature is created by Base64 encoding Header and Payload as:

data = encoded( Header ) + “.” + encoded( Payload )
signature = HMACSHA256 (data, secret key);

More details about JWT can be referred from https://jwt.io/

JWT in Theory

JWT authentication process can be broken into following 4 steps-

1) User is validated against database and claims are generated based on user’s role.
2) Payload containing claims or other user related data is signed with key to generate token and passed back to user.
3) User sends this token with each request, normally in header or cookies and then received token is decrypted to validate claim.
4) Once user is identified, User is allowed to access Resource server based on his claim.

Advantage of Token based authentication paradigm is that instead of storing authentication or authorization related information linked to every user in session, a single signing key is stored at the authorizing server/service. Task of Authorization can be delegated to any server making it completely decoupled. Users are identified by verifying the claims which was generated in the first step based on his/her permission. Claims can be trusted because it was generated by server in the first step and then was digitally signed using one of the algorithm like HMAC SHA256. It is also assured that rights or claims has not been tampered with.
Unique thing here which saves lots of memory and adds to scalability is that only one key is required at server for decrypting the token and identifying the user, no matter what number of users it supports.
After identification is done, identity should persist for the current user throughout the request. This is where every implementation may differ. Next section covers all the four steps involved while using JWT token with ASP.NET Web API.

Implementing JWT with Asp.Net Web API

There are various libraries available for the second and third steps (i.e generating and verifying token) in almost all the languages. If you wish to continue without any library and write all steps yourself, many blogs contain elaborated details about each of the steps.

I used System.IdentityModel.Tokens.Jwt library for generating and validating tokens.
To implement JWT in Web API, I created a filter for authentication which will be executed before every request. It will verify the token contained in the request header and will deny/allow resource based on token. Filter is as follows:

public class JWTAuthenticationFilter : AuthorizationFilterAttribute
    {

        public override void OnAuthorization(HttpActionContext filterContext)
        {

            if (!IsUserAuthorized(filterContext))
            {
                ShowAuthenticationError(filterContext);
                return;
            }
            base.OnAuthorization(filterContext);
        }
}

 

I over-rode OnAuthorization method of AuthorizationFilter and injected logic to verify the Token. (Note that, Starting MVC 5, Authentication Filter is also available)
Before I elaborate how IsUserAuthorized Method works which contains all the logic, let me introduce the authentication module which does all the work related to decrypting, encrypting, signing & verifying the token.

AuthenticationModule is where the downloaded library is used. There are various examples of using the libraries in several blogs. This stackoverflow answer also provides very good explanation. Hence, I am simply pasting my code snippets developed after the required modifications.

public class AuthenticationModule
    {
  private const string communicationKey = "GQDstc21ewfffffffffffFiwDffVvVBrk";
        SecurityKey signingKey = new InMemorySymmetricSecurityKey(Encoding.UTF8.GetBytes(communicationKey));


 // The Method is used to generate token for user
        public string GenerateTokenForUser(string userName, int userId)
        {


            var signingKey = new InMemorySymmetricSecurityKey(Encoding.UTF8.GetBytes(communicationKey));
            var now = DateTime.UtcNow;
            var signingCredentials = new SigningCredentials(signingKey,
               SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.Sha256Digest);

            var claimsIdentity = new ClaimsIdentity(new List<Claim>()
            {
                new Claim(ClaimTypes.Name, userName),
                new Claim(ClaimTypes.NameIdentifier, userId.ToString()),
            }, "Custom");

            var securityTokenDescriptor = new SecurityTokenDescriptor()
            {
                AppliesToAddress = "http://www.example.com",
                TokenIssuerName = "self",
                Subject = claimsIdentity,
                SigningCredentials = signingCredentials,
                Lifetime = new Lifetime(now, now.AddYears(1)),
            };

            var tokenHandler = new JwtSecurityTokenHandler();

            var plainToken = tokenHandler.CreateToken(securityTokenDescriptor);
            var signedAndEncodedToken = tokenHandler.WriteToken(plainToken);

            return signedAndEncodedToken;

        }

        /// Using the same key used for signing token, user payload is generated back
        public JwtSecurityToken GenerateUserClaimFromJWT(string authToken)
        {
        
            var tokenValidationParameters = new TokenValidationParameters()
            {
                ValidAudiences = new string[]
                      {
                    "http://www.example.com",
                      },

                ValidIssuers = new string[]
                  {
                      "self",
                  },
                IssuerSigningKey = signingKey
            };
            var tokenHandler = new JwtSecurityTokenHandler();

            SecurityToken validatedToken;

            try {

              tokenHandler.ValidateToken(authToken,tokenValidationParameters, out validatedToken);
            }
            catch (Exception)
            {
                return null;

            }
    
            return validatedToken as JwtSecurityToken;

        }

    private JWTAuthenticationIdentity PopulateUserIdentity(JwtSecurityToken userPayloadToken)
        {
            string name = ((userPayloadToken)).Claims.FirstOrDefault(m => m.Type == "unique_name").Value;
            string userId = ((userPayloadToken)).Claims.FirstOrDefault(m => m.Type == "nameid").Value;
            return new JWTAuthenticationIdentity(name) { UserId = Convert.ToInt32(userId), UserName = name };

        }
}

 

The Authentication module contains three methods-

1) GenerateTokenForUser is used for generating claim when user is authentic. This method contains all information we want to pass to and fro and uses secret key for signing based on algorithm specified. The encrypted information can be UserName, UserId, Roles, expiration time, etc.
2) GenerateUserClaimFromJWT receives the token from header and decrypts it to fetch claims.
3) PopulateUserIdentity is used to create the identity object after getting information from claims using library. I created object of JWTAuthenticationIdentity derived from GenericIdentity of System.Security.Principal namespace. This is so that I can store extra information like role, UserId, etc. The class looks like-

public class JWTAuthenticationIdentity : GenericIdentity
    {
        
        public string UserName { get; set; }
        public int UserId { get; set; }

        public JWTAuthenticationIdentity(string userName)
            : base(userName)
        {
            UserName = userName;
        }

       
    }

 

While logging for the first time, I invoked GenerateTokenForUser method of AuthenticationModule and returned the signed token when user is valid. (See, else part of below snippets)

[HttpPost]
        public HttpResponseMessage LoginDemo(string userName, string password)
        {

            MockAuthenticationService demoService = new MockAuthenticationService();
            UserProfile user = demoService.GetUser(userName, password);
            if (user == null)
            {
                return Request.CreateResponse(HttpStatusCode.Unauthorized, "Invalid User", Configuration.Formatters.JsonFormatter);
            }else
            {

                AuthenticationModule authentication = new AuthenticationModule();
                string token = authentication.GenerateTokenForUser(user.UserName, user.UserId);
                return Request.CreateResponse(HttpStatusCode.OK, token, Configuration.Formatters.JsonFormatter);
            }          

        }

 

I made the request through Postman (chrome extension). Returned token is shown in screenshot-

In case of invalid user, the result is shown as-

The returned token is passed as header in each request and the actual verification is done through IsUserAuthorized method in our custom filter.

        public bool IsUserAuthorized(HttpActionContext actionContext)
        {
            var authHeader = FetchFromHeader(actionContext); fetch authorization token from header
           
            if (authHeader != null)
            {
                var auth = new AuthenticationModule();
                JwtSecurityToken userPayloadToken = auth.GenerateUserClaimFromJWT(authHeader);

                if (userPayloadToken != null)
                {
                
                    var identity = auth.PopulateUserIdentity(userPayloadToken);
                    string[] roles = { "All" };
                    var genericPrincipal = new GenericPrincipal(identity, roles);
                    Thread.CurrentPrincipal = genericPrincipal; 
                    var authenticationIdentity = Thread.CurrentPrincipal.Identity as JWTAuthenticationIdentity;
                    if (authenticationIdentity != null && !String.IsNullOrEmpty(authenticationIdentity.UserName))
                    {
                        authenticationIdentity.UserId = identity.UserId;
                        authenticationIdentity.UserName = identity.UserName;
                    }               
                    return true;
                }

            }
             return false;

          
        }

 

A simple implementation to fetch authorization header-

    private string FetchFromHeader(HttpActionContext actionContext)
        {
            string requestToken = null;

            var authRequest = actionContext.Request.Headers.Authorization;
            if (authRequest != null)
            {
                requestToken = authRequest.Parameter;
            }

            return requestToken;
        }

 

IsUserAuthorized method is now self-explanatory. The steps performed are invoking second and third method of AuthenticationModule (as explained earlier) to populate JWTAuthenticationIdentity object which represents the identity of current user, creating GenericPrincipal and assigning it to current principle of request thread. Thus, all the user related information is set here. These user data can be retrieved from identity object of current request. Setting current principle through identity object is inspired from another similar blog on token (without JWT) based authentication. For more details, you can also refer to this blog .

Let’s try with incorrect token in the header. The method ShowAuthenticationError which is called through OnAuthorize method is described below:

       private static void ShowAuthenticationError(HttpActionContext filterContext)
        {
            var responseDTO = new ResponseDTO() { Code = 401, Message = "Unable to access, Please login again" };
            filterContext.Response =
            filterContext.Request.CreateResponse(HttpStatusCode.Unauthorized, responseDTO);
        }

 

The output in Postman is:

Now, if I pass the correct token generated, the output is shown below. It rightly fetches the list of books which was expected as per Action defined in our controller. Have a look-

[JWTAuthenticationFilter]
   public class DashboardController : BaseController
    {

        public HttpResponseMessage Get()
        {

            var listOfbooks = GetAllBooks();

            return Request.CreateResponse(HttpStatusCode.OK, listOfbooks);
        }

        private List<Books> GetAllBooks()
        {
            List<Books> book = new List<Books>();
            book.Add(new Books { Id = 1, Name = "ABC Books" });
            book.Add(new Books { Id = 2, Name = "XYZ Books" });
            book.Add(new Books { Id = 3, Name = "DEF Books" });
            return book;
        }

    }

Notice the controller decorated with JWTAuthenticationFilter attributes.


Concluding Points

JWT based approach for secure data transfer uses power of digital signature and hashing. The best usage I found is in authenticating/authorizing. It blends well with stateless protocol such as REST services and hence particularly useful for creating API services for mobile app development. In most of the implementation, it also saves Database lookup by storing piece of information like roles, UserId in claims. No need to mention the saving in memory spaces as compared to traditional approach.
As MVC and Web API provide way to inject our authorization logic through custom filters, JWT can be readily implemented. This was just very simplest implementation and I am looking forward for suggestions and better use cases for implementation.

I hope this information helps. Feel free to ask any queries in comments.

Thank you for taking out time to read my blog.

 

Related Articles

#Tech

NHibernate, Linq and Lazy Collections

For the past few months we have been busy building a services framework for one of our clients so that they can build all of their enterprise web services without ever having to worry about the cross cutting concerns and... Read more
#Tech

Page Redirects using Spring.NET

Who is responsible for page redirects in ASPNET MVP – The View or the Presenter None of the above, it is you :) On a serious note, it is the View as one shouldn’t pollute the Presenter with the page navigation... Read more
  • robin kumar

    There are lots of ambiguity between System.IdentityModel.Tokens and Microsoft.IdentityModel.Tokens
    Please provide code

    • Anjani Singh

      System.IdentityModel.Tokens is being used. I will share codebase for similar implementation

  • Muhammed M Khan

    Great article and effort.It would be better if you can provide the source code. Due to conflicts in the Namespaces, got stuck with lot of errors and beating the purpose of article.

    • Anjani Singh

      Thanks Muhammed.
      The state of codebase has been changed since i implemented. I will try to track that version of code and share within few days/weeks.

  • Muhusin Khan

    Hello Anjani, I have done some research and put some effort to make it work in .net 4.5 framework. I have modified some of the code in this sample due to namespace deprecation and framework updates.Thank God, it is working now and a good learning process. With your permission I will share this in my blog with updated code and my observations. I will definitely mention your courtesy for the base code and learning.Thanks a lot for your good effort .

    • Anjani Singh

      Thanks Muhusin. Please go ahead sharing it.