JWT Authentication in ASP.NET Core in Web API

Learn how to protect the Web API Endpoint Using JWT Authentication in ASP.NET Core. The JWT Authentication mechanism issues a digitally signed Bearer token to the Authenticated clients. The clients then need to present the token on every request in the Request header to gain access to the Protected Resources. The JWT Authentication typically used in Web API (REST API)

What is JWT Authentication

JSON Web Token (JWT) contains the claims of the user as name-value pair in the JSON Format. The issuer then digitally signs it using a private key (secret) before issuing it to the users.

JWT Token (Access Token)

JSON Web Token (JWT or Access Token) consists of three parts. Header, Payload & Signature

The Header contains information about the algorithm that the issuer uses to generate the Token.

The Payload contains the claims of the User.

Here the sub (Subject), iat (issued at) are predefined claims. Other predefined claims are iss (issuer), aud (Audience), exp (expiration time), nbf (not before), jti (JWT ID). Some of these claims are important on security point of view.

You can add as many public claims to it as you want. role, name and userdefined are the public claims in the above example.

The Issuer then encodes the Header and Payload with a secret and creates a Signature.

The final token is in the header.payload.signature format

The Issuer issues this token to the user after he is authenticated. The User needs to present this token in the Authorization header along with every request. The Issuer then uses the secret to verify the authenticity of the token before allowing access.

Another important point is that anyone will be able to decode & read the JWT token. Hence do not store sensitive data in a token. For Example, copy the above token and paste it in https://jwt.io/. You will be able to see the decoded token.

But no one will be able to temper with the token as it is signed with a secret.

Note that the issuer does not store the token. storing the token securely falls on the User of the token.

JWT Validation

Apart from encoding & signing the token. The JWT has a few other security-related properties in the form of predefined claims.

exp claim

exp stands for the expiration date of a JWT token. The token is invalid if the expiration date lies in the Past. Without an expiration date, the token is valid till the end of time. Without an expiration date, the only way to invalidate the token is by changing the secret. But changing the secret will invalidate all the tokens. Hence it is important to set the expiration date correctly and as short as possible.

iat claim

iat claim (issued at) indicates the time at JWT has been issued. This can also be used to reject the token if it token is not fresh.

nbf claim

nbf stands for not before. It holds the timestamp and indicates that the token is valid only after this time.

iss claim

iss claim(issuer) is a string value, which indicates the identity of the issuer who issued the token.

aud claim

The aud claim stands for the audience. It is a string value and indicates the intended user of the token.

Refresh Tokens

The JWT Tokens come with an expiration date using the exp claim. Without an expiration date, the tokens are valid for a long time. The server will trust a token as long its signature is valid and the token is not expired. If any hacker gets hold of the token, he can use it to pose as a genuine user. The token is still valid, even if the user changes his password. The Only way to invalidate it is by changing the secret, which invalidates all tokens.

Hence we need to set a shorter expiration date. But that will create problems for the genuine users as they need to re-login every time the token expires to get a new token.

This is where the refresh token comes into the picture. The issuer issues refresh tokens along with the access token. Unlike the access tokens, the issuer will store the refresh tokens securely. The refresh token also expires but will have a longer duration than the access token.

After the access token expires, the user will submit the refresh token to the issuer. The issuer validates the refresh token and issues a new access token along with a new refresh token. Also deletes the old refresh token so that the user cannot re-use it again.

All these will happen behind the scene without the knowledge of the user.

Testing JWT Authentication in ASP.NET Core

We will implement the JWT Authentication in an ASP.NET Core Web API Project. To test the API we will be making use of Postman, which you can download from https://www.postman.com/ . You can learn more about it from the Postman tutorial

Create ASP.NET Core Web.API Project

Open VS2019. Create a new Project. Select ASP.NET Core Web API Template. Name the project as ASPNetCoreJwtAuth. Select .NET 5.0 as Target Framework. Choose None for Authentication Type. Untick Enable OpenAPI support.

Run the Application and check if everything is OK.

Create Rest End Point

Create a new Empty API Controller under the folder Controllers. Name it is as JWTController

The Controller has two action methods. PrivateAPI & PublicAPI. We have Authorize attribute on PrivateAPI. Hence you need to login to read the data from PrivateAPI

Controllers/JWTController

Open the Postmaster Click on + symbol to create a new Request. Enter the URL https://localhost:44314/api/jwt/publicapi and click on Send. (Remember to change the port number). In the results tab, you will see the data from the API, and also the status code of the response is 200 ok.

jwt authentication access to public api

But, when we try our https://localhost:44314/api/jwt/privateAPI, we get “No authenticationScheme was specified, and there was no DefaultChallengeScheme found“. error.

This is because the Authorization Middltwere (UseAuthorization()). It tries to see if the user is authenticated & Authorized to view the privateAPI. To do that it needs to invoke the default Authentication Handler. Since our app does not have any Authentication Handlers registered, the code throws an error.

jwt authentication access to private api results in No authentication schema was specified

Setting up the database

Now, let us set up the database to store the User’s details & Also the refresh Tokens. We will make use of EF Core here. Run the following commands to install EF Core

Package Manager Console

Add the connection string in the appsettings.json file

appsettings.json

Create Entity Models for User & RefreshToken under the data folder

We are using the ef core seed data technique to Populate the user table with some data. Note that we are not storing the hashed Passwords, but you should not do that in real apps.

Data/User.cs

We store the Refresh Tokens in this table.

data/RefreshToken.cs

DbContext class

Data/ApplicationDbContext.cs

Register the ApplicationDbContext int the ConfigureServices method of the startup class.

ConfigureServices at startup.cs

Finally, run the EF Core Migrations to create the database.

JWT Authentication Service

The Microsoft.AspNetCore.Authentication.JwtBearer Package makes it easier to implement the JWT Bearer Authentication in ASP.NET Core. Hence we install it

Open the appsettings.json and add the following configuration values to create an access token & refresh token.

The secret is the key using which we are going to sign the Token. The secret is very important. Hence, you need to store it somewhere more secure than appsettings.json.

The issuer & audience settings are used to create the iss & aud claims.

accessTokenExpiration is time in minutes used to set the token expiration time using exp claim

refreshTokenExpiration is for refresh token expiration.

Create JWTAuthService in the folder Services. The purpose of the class to create access & refresh tokens.

Services/JWTAuthService.cs

Create JWT Token

We inject the jwtTokenConfig, which reads the configuration from the appsettings.json

BuildToken method creates the access token. We need to pass the list of claims to it.

We create the SigningCredentials from the Secret, which we get from appsettings.json

Create a new JwtSecurityToken. Value for issuer & audience from comes appsettings.json. The AccessTokenExpiration is added to the current time to get the token expires claim. We also need to pass the SigningCredentials to create the token.

Finally serializes the security token into a string and return it back.

Create Refresh Token

The method BuildRefreshToken builds the Refresh Token

There are two criteria to create a refresh token. The token must be reasonably unique & not easy to guess for anyone

Hence, we use a 32 byte long random number and convert it to base64 so that we can use it as a string

The GetPrincipalFrom Token recreates the User ( ClaimsPrincipal ) from the token.

We use the ValidateToken method of JwtSecurityTokenHandler class to do that. The ValidateToken method expects us to pass the token to verify, SigningCredentials & TokenValidationParameters to it.

We use this method to verify the access token while issuing the refresh token.

Signing In

The SignInManager signs in the user. It will use the JWTAuthService to create the Access & Refresh tokens.

Services/SignInManager.cs

We sign in the user using the SignIn Method.

We query the database to check to see if the user with the given email & password exists.

If the user exists. we will build the claim.

We use JwtAuthService to build the Access token & Refresh token

Save the RefreshTokens to database

RefreshToken method validates current Access Token & Refresh Token and generates the new Access token & Refresh token

First, we use the current Access Token to re-create the claimsPrincipal.

We access the id of the user from the claimsPrincipal and query to check if the user exists.

Next, we query the RefreshTokens table to check to of the Refresh token belongs to the user and not yet expired.

If all is ok, we build the Claims and create a new Access token, and Refresh token. The old Refresh token is deleted and the new token is saved to the database in its place.

Adding Claims

BuildClaims method builds the claims of the user. Here you can add additional claims to it.

Registering the Authentication Services

Now, we need to register the JWT bearer token authentication handler in the ConfigureServices method.

startup.cs

JWTAuthService & SignInManager is registered in DI container

jwtTokenConfig will read from jwt section of the appsettings.json. We also register as a Singleton service, so that you can access it in other services & controllers.

Finally, we register the JwtBearer Authentication handler using the AddJwtBearer

Authentication Middleware

Login & Refresh token End Points

Finally, let us build the login & Refresh token endpoints. Create the AccountController under the folder Controllers.

Controllers/AccountController.cs

Testing the JWT Bearer Authentication

Finally, we are ready to test our application

Open the postman and create a new request with following

And click on Send.

The Request will hit the api/account/login end point logins the user and returns Access & Refresh Token

Enter an invalid password and you should get the 401 Unauthorized response

Jwt Token generation demo in ASP.NET Core

Now, create a new request

Bearer token authorization demo

Change the token and send the request again and you will get the 401 Unauthorized response

Wait for 5 mins for the token to get expired and try again and you will get the 401 Unauthorized response.

To test the Refresh Token create a new Request. Change the Access token & Refresh token

You should be able to see the new Access & Refresh Token, provided the refresh token is not expired (10 min).

Accessing the User & Claims

We Read the ClaimsPrincipal from User Property of the HttpContext object

Remember we registered the Authentication Middleware in the Middleware pipeline using the UseAuthentication() Method.

When the Request arrives at the Authentication Middleware, it invokes the Default Authentication Handler to read the request and populate the HttpContext.User property

Remember in ConfigureServices , we registered the JWT Bearer Authentication handler and set it as default (DefaultAuthenticateScheme).

Authentication Middleware invokes the  AuthenticateAsync() method of the JWT Bearer Authentication handler to read the JWT token and uses it to populate the HttpContext.User property

All you need is to access the HTTPContext to the User & Claims.

For Example, in a Controller class, you can directly use the User or HttpContext as they are already available in the ControllerBase Class.

Summary

This tutorial showed you how to implement the JWT Authentication in ASP.NET Core. We used Postman to test our endpoints. You can build the Login & Register form in Front End tools like Angular /React Native etc.

References

  1. Security Issues in JWT Authentication
  2. JWT Web tokens

1 thought on “JWT Authentication in ASP.NET Core in Web API”

  1. Belarmino Vicenzo

    Authorization Type-> Authorization

    And _ctx.Users didn’t work here, was giving error because there were no Users on the context.
    so I added a DbSetUsers, error gone, but gave error on Postman, so I changed the DbSet to DbSet User and all worked okay.

Leave a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to Top