How to secure APIs with JWT in ASP.NET Core 5.0 [with source codes]

How to secure APIs with JWT in ASP.NET Core 5.0 [with source codes]

JWT stands for JSON Web Token, it’s an self-contained mechanism for securely transmitting information between parties as a JSON object (commonly known as ‘Token’). The token is digitally signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

Since the token is signed with a public/private key pairs, the signature certifies that only the party holding the private key is the one that signed it. So in this way authentication is done by JWT mechanism.

This tutorial is a part of series called JSON Web Token (JWT) in ASP.NET Core. There are 2 tutorials to master it:

Securing API with JWT

In this tutorial I will secure my APIs with JWT, this ensures that clients must send JWT token in the HTTP Authorization Header in order to access data from the API. The below figure explains the JWT working mechanism:

working of JWT
The Projects

In this tutorial I will create 2 projects for doing JWT implementation, both are built in ASP.NET Core 5.0. These projects are described below:

1. JWTAPI – this project returns a set of flight reservations in JSON format to the client. This project will validate the JWT token in order to authenticate the client requests.

2. JWTClient – this project will make the API requests to the “JWTAPI” project. The “JWTClient” will first create a JWT Token, add it to the HTTP’s Authorization header, and then will call the “JWTAPI”.

You can download both of these projects from the download link given at the bottom of this tutorial.

Create API Project and secure it with JWT

Let’s create the API Project called JWTAPI in step by step manner.

Step #1: Create a New ASP.NET Core 5.0 API project in Visual Studio 2019

In your Visual Studio 19, create a new ASP.NET Core Web Application and name it ‘JWTAPI’.

ASP.NET Core Application

Next, select ASP.NET Core 5.0 framework from the dropdown, and then select the ASP.NET Core Web API template as shown by the below image.

API template in VS

Finally click the create button to create this project.

There are 2 big API tutorials written by me which covers the API subject in ASP.NET Core from start to end. You can read them from the below links:

Step #2: Install JwtBearer package from Nuget and configure Startup.cs

You need to install the package called Microsoft.AspNetCore.Authentication.JwtBearer from NuGet. This package adds the middleware that enables an ASP.NET Core application to receive a Bearer Token in the Request Pipeline.

Microsoft.AspNetCore.Authentication.JwtBearer

Next, configure JWT authentication in the project. To do this, register a JWT authentication schema by using AddAuthentication() method in the ConfigureServices() method of Startup.cs file. The code which you have to add is given below:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors();
    services.AddControllers();
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        options.SaveToken = true;
        options.RequireHttpsMetadata = false;
        options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidAudience = "https://www.yogihosting.com",
            ValidIssuer = "https://www.yogihosting.com",
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MynameisJamesBond007"))
        };
    });
}

Explanation: The ‘AuthenticationOption’ has 3 properties:

  • DefaultAuthenticateScheme
  • DefaultChallengeScheme
  • DefaultScheme

These 3 are set to the default value JwtBearerDefaults.AuthenticationScheme. By the way this is the Bearer.

Next, I used the AddJwtBearer() method to configure the JwtBearerOptions as shown below:

.AddJwtBearer(options =>
{
    options.SaveToken = true;
    options.RequireHttpsMetadata = false;
    options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidAudience = "https://www.yogihosting.com",
        ValidIssuer = "https://www.yogihosting.com",
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MynameisJamesBond007"))
    };
});

I used the TokenValidationParameters property to specify how to token will be validated on the server. For this I set true for the Issuer and Audience.

The most important property here is the IssuerSigningKey that is used to set the security key. Through this key the token is signed by the client using JWT. The server also uses it to validate the token which it gets in the client request header.

ValidAudience and ValidIssuer can have any values.

I am using ‘MynameisJamesBond007’ as my security key, you can use any key you want (min 16 characters in length).

Next, go to the Configure() method and tell your app to use authentication and authorization. You add the below 2 lines of code after the app.UseRouting().

app.UseAuthentication();
app.UseAuthorization();

Step #3: Create Model & Controller

Now I will create the API method to return data to the client in JSON. This data will be a list of ‘Flight Reservation’. So create a new class called Reservation.cs preferably inside the ‘Models’ folder, and add to it the code given below:

public class Reservation
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string StartLocation { get; set; }
    public string EndLocation { get; set; }
}

Next, create a new controller called ReservationController.cs. This controller will have the task to return reservations to the client whenever request to the API is made by the client.

The full code of this controller is given below:

[Route("[controller]")]
[ApiController]
[Authorize]
public class ReservationController : ControllerBase
{
    [HttpGet]
    public IEnumerable<Reservation> Get() => CreateDummyReservations();

    public List<Reservation> CreateDummyReservations()
    {
        List<Reservation> rList = new List<Reservation> {
            new Reservation { Id=1, Name = "Ankit", StartLocation = "New York", EndLocation="Beijing" },
            new Reservation { Id=2, Name = "Bobby", StartLocation = "New Jersey", EndLocation="Boston" },
            new Reservation { Id=3, Name = "Jacky", StartLocation = "London", EndLocation="Paris" }
            };
        return rList;
    }
}

Explanation : I have marked this controller with [Authorize] attribute of the Microsoft.AspNetCore.Authorization namespace. This is done specifically in order to secure the API with JWT token. I will tell more about it later on.

I have created some dummy reservations inside the CreateDummyReservations () function and these are returned by the API in JSON. The HttpGet method of the API does this work of returning these reservations in JSON.

[HttpGet]
public IEnumerable<Reservation> Get() => CreateDummyReservations();

You have successfully secured your API with JWT. Now request from the clients will be authenticated beforehand and only then the Web API will provide them with the reservation data. In technical terms – the Web API will authenticate the request from the clients and if these requests contain a correct JWT token then only the Web API will authorize them.

Test

Let us perform some testing. Comment out the [Authorize] attribute on the ‘ReservationController’ by applying ‘//’ before it. Next, run your application on visual studio. When the browser starts, open the URL of the ‘ReservationController’ which in my case is:

https://localhost:44314/Reservation

You will see the JSON containing the reservations as shown below:

reservation json

Now remove the ‘//’ before the [Authorize] attribute (i.e. un-comment it) and refresh the same URL. This time you will see Http Error 401 which tells – you are unauthorized to access the reservation controller. Congratulations, JWT is implemented successfully on your JWTAPI project.

http-error-401

Next, I will create a client project from where JWT Bearer Token will be created and added to the HTTP Authorization Header, and then the API is called. So let us proceed.

Client Project making API request by using JWT Token in HTTP request

Let us create the Client project called JWTClient (this will make API Calls) to the JWTAPI project.

Step #1: Create a New ASP.NET Core 5.0 Web Application project in Visual Studio 2019

Like what you did before, create a new ASP.NET Core Web Application and name it JWTClient.

Next, select ASP.NET Core 5.0 framework from the dropdown, and then select the template that says Web Application (Model-View-Controller). Click the create button to create this project.

MVC-template-in-VS

Step #2: Install package – ‘IdentityModel.Tokens.Jwt’ from NuGet

The first thing to do is to install the package called IdentityModel.Tokens.Jwt. This package is used to Create, Serialize and Validate JWT Tokens. Check the screenshot from NuGet:

IdentityModel.Tokens.Jwt

Step #3: Create Model

Create a class called Reservation.cs inside the Models folder. This class will hold the API response data i.e. the flight reservations returned by the API. It is the same reservation class which we used in the earlier project. I hope you remember it!

public class Reservation
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string StartLocation { get; set; }
    public string EndLocation { get; set; }
}

Step #4: Create JWT Token and make API request

Now you are ready to make API Calls. So create a new controller called CallAPIController.cs. Add ‘Index’ action method of type [HttpPost] to it. In this action method we will create a JWT Token and then add it to the HTTP Authentication header, and after that we make the API call.

The code of this action method is given below:

[HttpPost]
public async Task<IActionResult> Index(string key)
{
    var tokenString = GenerateJSONWebToken(key);
    List<Reservation> reservationList = new List<Reservation>();
    using (var httpClient = new HttpClient())
    {
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenString);
        using (var response = await httpClient.GetAsync("https://localhost:44314/Reservation")) // change API URL to yours 
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            reservationList = JsonConvert.DeserializeObject<List<Reservation>>(apiResponse);
        }
    }

    return View("Reservation", reservationList);
}

private string GenerateJSONWebToken(string key)
{
    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
    var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

    var token = new JwtSecurityToken(
        issuer: "https://www.yogihosting.com",
        audience: "https://www.yogihosting.com",
        expires: DateTime.Now.AddHours(3),
        signingCredentials: credentials
        );

    return new JwtSecurityTokenHandler().WriteToken(token);
}
Do you know ASP.NET Core Identity. See this Username, Email & Password Policy in ASP.NET Core Identity

Explanation: Let us now understand how it all works. The user has to enter the correct security key to the text box presented on the view. Recall, this security key is MynameisJamesBond007.

The GenerateJSONWebToken(string key) function is provided with this security key in the argument. It creates a JWT Token by assigned with the values of issuer, audience, expires and signingCredentials. Check this codes which do these things.

var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

var token = new JwtSecurityToken(
    issuer: "https://www.yogihosting.com",
    audience: "https://www.yogihosting.com",
    expires: DateTime.Now.AddHours(3),
    signingCredentials: credentials
    );

Remember that tokens needs to be created with the correct security key else they will not be authenticated by the Web API. If the user enters incorrect security key then JWT will not authorize the request and so the controller will never be called by the client’s request.

Also notice the issuer and audience values are the same which we have kept in the JWTAPI project.

The JWT Token is returned by the GenerateJSONWebToken() function and the variable ‘tokenString’ stores it.

Next, I create the HttpClient class object and I adds the JWT Token to the HTTP authorization header like this:

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenString);

And finally make the call to the Web API at the URL – https://localhost:44314/Reservation by the below code.

using (var response = await httpClient.GetAsync("https://localhost:44314/Reservation"))
{
    string apiResponse = await response.Content.ReadAsStringAsync();
    reservationList = JsonConvert.DeserializeObject<List<Reservation>>(apiResponse);
}

Step #5: Create Views

I will need 2 views, the first one is the Index view inside the Views/CallAPI folder. This view will contain a text boxe for entering the Security Key.

@{ ViewBag.Title = "Login";}
<h2>Login</h2>

<form method="post">
    <table class="w-25 table table-striped table-bordered">
        <tbody>
            <tr>
                <td>Security Key</td>
                <td><input type="text" name="key" /></td>
            </tr>
            <tr>
                <td colspan="2">
                    <button>Submit</button>
                </td>
            </tr>
        </tbody>
    </table>
</form>

The second view is the Reservation view which is also inside the Views/CallAPI folder. This view will show the reservations inside an html table once these reservations are received by the JWTClient project. It’s code is given below:

@model IEnumerable<Reservation>
@{ ViewBag.Title = "All Reservations";}

<h2>All Reservations</h2>
<table class="table table-sm table-striped table-bordered m-2">
    <thead><tr><th>ID</th><th>Name</th><th>Start Location</th><th>End Location</th></tr></thead>
    <tbody>
        @if (Model != null)
        {
            foreach (var r in Model)
            {
                <tr>
                    <td>@r.Id</td>
                    <td>@r.Name</td>
                    <td>@r.StartLocation</td>
                    <td>@r.EndLocation</td>
                </tr>
            }
        }
    </tbody>
</table>

Perfect, now it’s now time to test it.

I have also created the same tutorial using jQuery where you do not see any page refresh i.e. all work asynchronously. Check it after you finished this tutorial – How to call a JWT secured APIs with jQuery AJAX
Test

Coming to the testing part, ensure you are running the JWTAPI project in visual studio.

Next, run your client project which is JWTClient in visual studio and open it’s ‘CallAPI’ controller’s URL which in my case is https://localhost:44361/CallAPI.

You see the login screen where you enter the Security key as “MynameisJamesBond007”.

login screen

Click the Submit button, which will make the API call and show all the flight reservations. Check the below image:

jwt secured api response data

Now let us see what happens when JWT authentication fails. So go to the login screen once again and this time enter the wrong Security key – “007MynameisJamesBond”. On clicking the submit button you will notice that this time no reservations are send by the API. The html table shows no records.

jwt authentication failed

The full JWT integration is completed and is working successfully.

You can download the full codes of this tutorial from the below link:

Download

Adding Custom Information to the JWT Token through Claims

JWT Claims are pieces of information added to the token. For example, a JWT token may contain a claim called Name that asserts that the name of the user whose reservation is to be checked is say “Bobby”.

Let us modify things we created before to include JWT Claims. So, in the Index view of JWTClient project, add a new row to the table to contain a new text box for adding name of the person. See the added code shown in highlighted way.

<table class="w-25 table table-striped table-bordered">
    <tbody>
        <tr>
            <td>Security Key</td>
            <td><input type="text" name="key" /></td>
        </tr>
        <tr>
            <td>Person</td>
            <td><input type="text" name="person" /></td>
        </tr>
        <tr>
            <td colspan="2">
                <button>Submit</button>
            </td>
        </tr>
    </tbody>
</table>

Next, change the CallAPIController code which is shown in highlighted way below:

[HttpPost]
public async Task<IActionResult> Index(string key, string person)
{
    var tokenString = GenerateJSONWebToken(key, person);
    List<Reservation> reservationList = new List<Reservation>();
    using (var httpClient = new HttpClient())
    {
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenString);
        using (var response = await httpClient.GetAsync("https://localhost:44314/Reservation")) // change API URL to yours 
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            reservationList = JsonConvert.DeserializeObject<List<Reservation>>(apiResponse);
        }
    }

    return View("Reservation", reservationList);
}

private string GenerateJSONWebToken(string key, string person)
{
    var claims = new[] {
        new Claim("Name", person)
    };

    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
    var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

    var token = new JwtSecurityToken(
        issuer: "https://www.yogihosting.com",
        audience: "https://www.yogihosting.com",
        expires: DateTime.Now.AddHours(3),
        signingCredentials: credentials,
        claims: claims
        );

    return new JwtSecurityTokenHandler().WriteToken(token);
}

We now have one more parameter for getting the values of “Person” in the Index action. This parameter value is passed on to the GenerateJSONWebToken(key, person) function, and it creates a claim by the name of “Name”. This claim is added to the token as shown by the highlighted code given below:

private string GenerateJSONWebToken(string key, string person)
{
    var claims = new[] {
        new Claim("Name", person)
    };

    //…

    var token = new JwtSecurityToken(
        issuer: "https://www.yogihosting.com",
        audience: "https://www.yogihosting.com",
        expires: DateTime.Now.AddHours(3),
        signingCredentials: credentials,
        claims: claims
        );

    return new JwtSecurityTokenHandler().WriteToken(token);
}

Next, I use this ‘Name’ claim value to filter out my flight reservations. So update the ReservationController.cs of the API which now grabs this claim’s value through the HttpContext.User.Claims class, and then filters out the reservation so that reservation’s name matches exactly to the ‘Name’ value assigned on the claim.

The updates code which does this work is shown below:

[HttpGet]
public IEnumerable<Reservation> Get()
{
    var claims = HttpContext.User.Claims;
    return CreateDummyReservations().Where(t => t.Name == claims.FirstOrDefault(c => c.Type == "Name").Value);
}

I have created a small video to show this working:

jwt claims working video
Conclusion

JWT is a great way to secure your API without having to spend much time in integration process. I tried to show how easy the whole procedure is. I hope you like this tutorial so please share it on your reddit, facebook, twitter and other social accounts.

SHARE THIS ARTICLE

  • linkedin
  • reddit
yogihosting

ABOUT THE AUTHOR

I hope you enjoyed reading this tutorial. If it helped you then consider buying a cup of coffee for me. This will help me in writing more such good tutorials for the readers. Thank you. Buy Me A Coffee donate

Comments

  1. Eduardo says:

    Hi i would be really interesting in an article with these features:
    – A secured webapi (project): ASP.NET WebApi (net core 3.1) with JWT authentication / autorization an roles.
    – A secured client (project): ASP.NET MVC Core 3.1 application with his own authentication and roles, which invokes the secured webapi.
    – The secured client, should invoke the secured webapi, generate token and refresh tokens.

    I could make a small donation if you provide a example / solution with those requirements. Pleas let me know if possible.

    1. yogihosting says:

      Hello Eduardo, Right now I don’t have any project which does this work. You can download the source code of this tutorial and will have to add these features by your own. Check the JWT authentication docs to get more info on them. Slowly and steadily you will be able to create all these features by your own.
      Thank you.

  2. Pedro Martins says:

    Hello Yogi,
    love you tutorial but i am somewhat confused in
    this one…
    (How to secure APIs with JWT in ASP.NET Core 3.1)

    When i need to connect to a API with autentication and get a token its the api that checks my user and pass and give me a token for the session.

    But in your example you put the user verification and token criation on the client side… I think you inverted things!

    1. yogihosting says:

      Hello Pedro Martins,

      In the client project the call to the API is made. JWT Token is also created on the same step. Download the source codes and run the application from Visual Studio, put breakpoints on the Controller code and then debug. This way you will understand the full code very easily.

      Thank you.

      1. Pedro Martins says:

        Hello Yogi, but shouldn´t the username validation bbeing done on the Api side and should it result in the api also supply the token to the Client?
        In your example its the client that validates the username and password are correct and crates the token.
        Thanks in advance,
        Pedro

        1. yogihosting says:

          Hello Pedro,

          Yes, you can do username validation on the API side. The client side main work is JWT Token generations done from the line var tokenString = GenerateJSONWebToken(). So API will check this token for the request it receives.

          Thank you.

  3. rajeev says:

    first of all thanku for making such of tutorial which is very helpful when i used jQuery for taking data to api nothing is happened.

    1. yogihosting says:

      Hello Rajeev,
      I think you may be getting some jQuery errors please check the console of the browser for errors. Make sure the URL of the action in jQuery ajax method is correct. Also try applying breakpoint to debug.
      thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *