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

How to secure APIs with JWT in ASP.NET Core 3.1 [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 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 so that clients have to 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

There are 2 projects for doing this JWT implementation, they are built in ASP.NET Core 3.1. These projects are described below:

1. The JWTAPI project that 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. The JWTClient project from where the API requests are made. This project will first create the JWT Token and then adds it to the HTTP’s Authorization header, and then consumes the API.

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 3.1 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 3.1 framework from the dropdown, and then select the ‘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. In the below image I have shown the screenshot of the installation procedure.
Microsoft.AspNetCore.Authentication.JwtBearer
Next, you need to 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:
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 and DefaultScheme. These 3 are set to the default value of the AuthenticationScheme property in the JwtBearerAuthenticationOptions object, by the way this is Bearer. Next, use the AddJwtBearer() method to configure the ‘JwtBearerOptions’ like this:
.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 values 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 way. The server also uses it to validate the token which it gets from the client request.

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 to lines of code after the app.UseRouting().

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

Step #3: Create Model & Controller

Now I will create the API method that will return data to the client in JSON, which in my case will be a list of ‘Flight Reservation’. So create a class called Reservation.cs preferably inside the ‘Models’ folder, and add to it the code shown 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]")]
[Authorize]
public class ReservationController : Controller
{
    [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 JSON data of reservations:

[HttpGet]
public IEnumerable<Reservation> Get() => CreateDummyReservations();
Congratulations: You have successfully secured your API with JWT. Now request from the clients will be authenticated beforehand and then the API will provide them with data.
Test
Let us test how it works so far. So first comment out the [Authorize] attribute on the ‘ReservationController’ by applying ‘//’ before it, and 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 and re-open the same URL in the browser. This time you will see Http Error 401 which tells – you are unauthorized to access the reservation controller.
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 API is called for.

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

Let us create the Client project called JWTClient (this will make API Calls) in step by step manner.

Step #1: Create a New ASP.NET Core 3.1 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 3.1 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. The code is 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; }
}

Step #4: Create JWT Token and make API request i.e inside the Controller

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 I first create a JWT Token and then add it to the HTTP Authentication header, after that I make the API call.

The code of this action method is given below:

[HttpPost]
public async Task<IActionResult> Index(string username, string password)
{
    if ((username != "Secret") || (password != "Secret"))
        return View((object)"Wrong Username or Password");

    var tokenString = GenerateJSONWebToken();
    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"))
        {
            string apiResponse = await response.Content.ReadAsStringAsync();
            reservationList = JsonConvert.DeserializeObject<List<Reservation>>(apiResponse);
        }
    }

    return View("Reservation", reservationList);
}

private string GenerateJSONWebToken()
{
    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MynameisJamesBond007"));
    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);
}
Explanation: Let us now understand how it all works. The user has to enter his correct username and password from the view. These are checked, and only correct ones are allowed to make API call. I am doing a demo check in here like this:
if ((username != "Secret") || (password != "Secret"))
    return View((object)"Wrong Username or Password");
When the credentials are correct then the GenerateJSONWebToken() function is called where the JWT Token is created by assigning values to the issuer, audience, expires and signingCredentials properties of the JwtSecurityToken class, see the below code where I am doing all these things:
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("MynameisJamesBond007"));
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);

You could see I am using my security key which is ‘MynameisJamesBond007’ and Security Algorithm called HmacSha256 to create this token.

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 API call to the URL – https://localhost:44314/Reservation as shown below:
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 kept inside the ‘Views/CallAPI’ folder. The ‘Index’ view code is given below:

@model string
<h2>Login</h2>
@{
    if (Model != null)
    {
        <div class="alert alert-danger">@Model</div>
    }
}

<form method="post">
    <table class="w-25 table table-striped table-bordered">
        <tbody>
            <tr>
                <td>Username</td>
                <td><input type="text" name="username" /></td>
            </tr>
            <tr>
                <td>Password</td>
                <td><input type="text" name="password" /></td>
            </tr>
            <tr>
                <td colspan="2">
                    <button>Submit</button>
                </td>
            </tr>
        </tbody>
    </table>
</form>

The second view is the ‘Reservation’ view which is also kept inside the ‘Views/CallAPI’ folder. 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>
        @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>

Congratulations, your API consuming code is complete. 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, make sure you run your JWTAPI project so that you can consume your API. Next run your JWTClient project and go to the ‘CallAPI’ controller’s URL which in my case is ‘https://localhost:44361/CallAPI’

First you see the login screen where you enter both username and passwords as ‘Secret’.

login screen

Next, 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
This completes all the integration and testing of JWT project. Download the full source code for both the projects:

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 authenticating is “Bobby”.

Let me show you how to do this thing. Go to the client project and inside the GenerateJSONWebToken() function create a claim and add it to the token as shown below:

private string GenerateJSONWebToken()
{
    var claims = new[] {
        new Claim("Name", "Bobby"),
        new Claim(JwtRegisteredClaimNames.Email, "[email protected]"),
    };

    //…

    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 API to fetch this claim’s value through the HttpContext.User.Claims class, and then filter 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 video
Conclusion
JWT is a great way to secure your API without having to spend too much time in integration process. I tried to show you how easy the whole procedure is. I hope you like this tutorial so please share it on your facebook, twitter and other social accounts.

Share this article -

yogihosting

ABOUT THE AUTHOR

This article has been written by the Technical Staff of YogiHosting. Check out other articles on "ASP.NET Core, jQuery, EF Core, SEO, jQuery, HTML" and more.

Leave a Reply

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