Generate/Validate JSON Web Tokens(JWT) in ASP.NET Core

Introduction

Last week, there was a requirement within one of our backend teams to generate and validate JWT without using and Identity Server. I vividly remember that last year I have seen such same requirement in another company, and they have manually taken so many steps, and it was a painful process for them to achieve that goal. Here in this article we will discuss how one might have such feature in their API using built-in classes and functionalities in ASP.NET Core.

What is JWT

JSON Web Token (JWT) is an Internet standard for creating data with optional signature and/or optional encryption whose payload holds JSON that asserts some number of claims. The key can be signed using various mechanisms, with a secret key, or a public/private key pair. Then later on, this mechanism will help to validate the token and make sure that it is what it claims. For more information regarding JWT, see https://jwt.io/introduction/

Generate JWT

ASP.NET Core provides classes to facilitate and secure the way developers intend to generate or validate JWTs. One of the main participants in this process is JwtSecurityTokenHandlerclass; Its responsibility is to create tokens based on JwtSecurityToken or a description of the token by SecurityTokenDescriptor, in the latter the programmer describes what information should the token contain and what the signing credentials, algorithm, should be; with the JwtSecurityToken the developer explicitly sets headers, payload, and signing mechanism using several classes provided by the framework, for instance, JwtHeader and JwtPayload classes. Let’s see that in action.

You need to install a NuGet package to be able to generate or validate JWT, to do so add the following package:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer --version 9.0.0

and add the following code to the Login action of the controller Account

var securityKey = new SymmetricSecurityKey(
        Encoding.UTF8.GetBytes("7h!$S40u1d83@$7r0n9P@5$Word"));
var header = new JwtHeader(
        new SigningCredentials(
                securityKey,
                SecurityAlgorithms.HmacSha512Signature
        ));

var claims = new[]
{
    new Claim(ClaimTypes.NameIdentifier, "user1"),
    new Claim(ClaimTypes.Role, "admin"),
};
var payload = new JwtPayload(
                        issuer: "http://localhost:6001",
                        audience: "my-api",
                        claims: claims, null,
                        expires: DateTime.UtcNow.AddDays(7),null);

var token = new JwtSecurityToken(header, payload);

var tokenHandler = new JwtSecurityTokenHandler();

return tokenHandler.WriteToken(token);

Run the application and try to reach the account/login endpoint to test the output, either by using swagger or running the following curl command:

curl -X POST "https://localhost:6001/Account/login" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"username\":\"shahab\",\"password\":\"somepassword\"}"

Get the output and check it in jwt.io. So far so good, now we have a valid JSON Web Token, which indicates that our user is also in the admin role. Now it is time to validate the token when the user intends to run protected endpoints. Put an [Authorize] attribute on top of other controllers, and let’s see how we could go further.

Validate JWT

Now that we have issued a JWT, it is time to pass it back to the server to be able to access protected endpoints; now, the asp.net application at the endpoint should be able to 1. Validate the token and 2. Grab the information, claims, hidden in that token and set them appropriately. To do so, use the following code in the ConfigureServices of the Startup class:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidIssuer = "http://localhost:6001",
                ValidAudience = "my-api",
                IssuerSigningKey = new SymmetricSecurityKey(
                    Encoding.UTF8.GetBytes("7h!$S40u1d83@$7r0n9P@5$Word"))
            };

            options.Events = new JwtBearerEvents
            {
                OnMessageReceived = ValidateToken
            };
        });

PS: In the sample on GitHub, some configuration files are placed in appsettings.json and will be read from there.

PS: Needless to say that all sensitive data should NOT be stored as plain texts or in the source controller. In this article, and code sample, it is only for simplicity.


First we enabled authentication services in our application and then indicated that we want to use a bearer token, added some options that will be used for validating the bearer token, and then assigned a method to do the actual validation when a message is received in the pipeline.

public static Task ValidateToken(MessageReceivedContext context)
{
    try
    {
        context.Token = GetToken(context.Request);

        var tokenHandler = new JwtSecurityTokenHandler();
        tokenHandler.ValidateToken(context.Token, context.Options.TokenValidationParameters, out var validatedToken);

        var jwtSecurityToken = validatedToken as JwtSecurityToken;

        context.Principal = new ClaimsPrincipal();

        var claimsIdentity = new ClaimsIdentity(jwtSecurityToken.Claims.ToList(),
                "JwtBearerToken", ClaimTypes.NameIdentifier, ClaimTypes.Role);
        context.Principal.AddIdentity(claimsIdentity);

        context.Success();

        return Task.CompletedTask;
    }
    catch (Exception e)
    {
        context.Fail(e);
    }

    return Task.CompletedTask;
}

First grab the token from the request, it could be in an Authorization header with a string value of Bearer plus the token, or somewhere in the query string. After getting the token we used a JwtSecurityTokenHandler and the options defined previously, which are available through the context to validate the bearer token; After that we create a claim identity and set which claims to set for name and role types.

Now, by adding an Authorization header with the value of Bearer plus your generated token, you could access endpoints that are secured via Authorization attribute.

Conclusion

ASP.NET Core has so many built-in libraries and mechanisms to support developers for a better implementation of the functional and non-functional requirements; classes you’ve seen so far in this article are one of the many, just to support JSON Web Tokens. I hope you find this article fruitful, you could also find the source code on GitHub Enjoy coding 😉

Buy Me a Coffee at ko-fi.com

Custom Configuration Providers in ASP.NET Core

A colleague of mine had a requirement in which he was interested to put the configuration settings of an ASP.NET Core application inside a SQL Server table and read them at startup of the application with a mechanism similar to what we already have for JSON files; also he wanted to have the ability that these variable being overridden or override other settings if applicable. In this article, I am going to describe how that could be achievable and how to implement such feature.

Get started with ASP.NET Core for non-C# developers

I had a discussion on a meet-up a month ago with a friend of mine, and he was telling me it is not really easy or clear how one could create a simple web application in .NET and C#. Hopefully this post is going to help that friend of mine! 😊

Explore Global Query Filters in EF Core

In this article we are going to check one of the features of Entity Framework Core, Global Query Filters; this was introduced first in EF Core 2.0 and is just a query predicate that will be appended to the end of where clause for queries on entities for which this feature has been activated.

An error has occurred. This application may no longer respond until reloaded. Reload x