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
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:
Payload looks like:
The signature is created by Base64 encoding Header and Payload as:
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:
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.
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-
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)
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.
A simple implementation to fetch authorization header-
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:
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-
Notice the controller decorated with JWTAuthenticationFilter attributes.
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.