Best way to Implement JWT Authentication C# .NET Core Web API

In this blog post will explore JWT authentication C# in more detail. Including its benefits, best practices, and how to implement JWT authentication in Web API. Whether you are a developer looking to secure your web API or an IT professional interested in the latest authentication technologies. This guide will provide the information you need to get started with JWT authentication C#.

Best way to Implement JWT Authentication C# .NET Core Web API

To understand token-based authentication, it’s important to first be familiar with the concepts of authentication and authorization: 

Authentication: It is the process of verifying the identity of a user or system. This involves providing evidence, such as a username and password, to prove that you are who you claim to be. 

Authorization: It is the process of specifying what actions a user or system is allowed to perform once they have been authenticated. This involves assigning access rights and privileges to resources. Like files, databases, or web APIs, to ensure that only authorized users can access them. 

By understanding these concepts, you will be better equipped to understand how JWT authentication works. Also how it can help secure your applications and services.

What is JWT?

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

JSON Web Tokens consist of three parts separated by dots (.):

Header: The header typically consists of two parts: the type of the token, which is JWT, and the signing algorithm being used, such as HMAC SHA256 or RSA.

Payload: The second part of the token is the payload, which contains the claims. Claims are statements about an entity (typically, the user) and additional data. There are three types of claims: registered, public, and private claims.

Signature: To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.

What is JWT

What is JWT authentication?

The JWT stands for JSON Web Token. JWT authentication is a popular method for securing web APIs, mobile applications, and other online services. 

JWT is a compact, self-contained way of transmitting information between parties as a JSON object. JWT is widely used because it is lightweight, stateless, and can be easily integrated with other systems.

JWT authentication is a popular method for securing web APIs, mobile applications, and other online services. 

It involves the use of a token or a key that is generated by the server and sent to the client after the user logs in. The client then uses this token to access protected resources on behalf of the user. 

JWT authentication is a secure method for authentication. Because the token contains a signature that ensures that the token was not tampered with during transmission.


How does JWT Authentication Work? 

  1. User logs in: The user sends their login credentials to the server. Which verifies their identity.
  2. Token generation: After successful login, the server generates a JWT token. It contains the user’s identity, access level, or any other relevant information. This token is digitally signed using a secret key to ensure that it cannot be tampered with.
  3. Token sent to the client: The server sends the JWT token back to the client as a response to the login request. The client stores this token locally, either in a cookie or in local storage.
  4. Token inclusion in requests: For subsequent requests to the server, the client includes the JWT token in the request headers. This token serves as proof of the user’s identity and access level.
  5. Token verification: When the server receives a request that includes a JWT token. It verifies the token’s signature using the secret key. It also checks the token’s expiration time and revocation status to ensure that the token is still valid.
  6. Granting access: If the JWT token is valid, the server grants the requested access on behalf of the user. If the token is not valid, the server denies the access or action and returns an error response.

Overall, JWT authentication is a secure and efficient way to handle user authentication and authorization in web applications and APIs. By using a digitally signed token to verify the user’s identity and access level.


Benefits of JWT Authentication?

  • Self-contained token: The JWT token is self-contained. Which means it contains all the necessary information about the user’s identity and access level. This makes it easy to transmit between different systems and applications. Also, making it a popular choice for securing web APIs and microservices.
  • High level of security: Because the JWT token is signed using a secret key, it provides a high level of security. Any tampering with the token would invalidate the signature. That makes it difficult for attackers to gain unauthorized access.
  • Stateless: JWT authentication is stateless, which means that the server does not need to maintain any session information. This makes it easier to scale applications and reduces the load on servers. As they do not need to store session information for each user.
  • Cross-platform compatibility: JWT is a widely adopted industry standard. Which means it can be easily implemented across different programming languages and platforms. This makes it a versatile and interoperable solution for securing web APIs and microservices.
  • Reduced network overhead: JWT authentication reduces the network overhead by sending the token as a header in each request. This eliminates the need for the server to retrieve session information for each request. Which reduces the network traffic and improves the application’s performance.

Implementing JWT Authentication in Web API C# (.NET) 

Here is a visual representation of the implementation that we are going to carry out.

Implementing JWT Authentication in Web API C# (.NET)

To implement JWT authentication C# in Web API, you’ll need to follow these steps.

Step 1: Create a new .NET 6 web API project

To get started, create a new .NET 7 web API project. You can do this using the dotnet CLI or via Visual Studio. Once you have created your project, make sure that it is up to date with all the latest .NET 7 packages.

Step 2: Install the necessary packages

In order to implement token-based authentication, you will need to install the Microsoft.AspNetCore.Authentication.JwtBearer package. This package provides middleware that can validate JSON Web Tokens (JWTs).

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
Step 3: Add Configuration details in appsettings.json

Add the following JWT configuration in appsettings.json file:

"JWT": {
  "Key": "A super secret string that can be whatever you like",
  "Issuer": "https://mytechnicalskills.com/",
  "Audience": "mytechnicalskills.com"
}
Step 4: Configure authentication in Program.cs

In the Program.cs file, you will need to configure authentication. Here is an example configuration:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;

namespace JWT.MyTechnicalSkills
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            builder.Services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(o =>
            {
                var Key = Encoding.UTF8.GetBytes(builder.Configuration["JWT:Key"]);
                o.SaveToken = true;
                o.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    ValidIssuer = builder.Configuration["JWT:Issuer"],
                    ValidAudience = builder.Configuration["JWT:Audience"],
                    IssuerSigningKey = new SymmetricSecurityKey(Key)
                };
            });

            // Add services to the container.
            builder.Services.AddTransient<IUserService, UserService>();

            builder.Services.AddControllers();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();

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

            app.MapControllers();

            app.Run();
        }
    }
}

This code configures authentication to use the JWT bearer middleware. It also sets up the token validation parameters, which include things like the issuer and audience of the JWT.

Step 5: Generate JWTs

To generate JWTs, you will need to create a controller that handles user authentication. Here is an example controller:

using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace JWT.MyTechnicalSkills.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AuthenticationController : ControllerBase
    {
        private readonly IConfiguration _configuration;
        private readonly IUserService _userService;

        public AuthenticationController(IConfiguration configuration,
            IUserService userService)
        {
            _userService = userService;
            _configuration = configuration;
        }

        [HttpPost]
        public IActionResult Authenticate([FromBody] LoginModel model)
        {
            var user = _userService.Authenticate(model.Username, model.Password);

            if (user == null)
            {
                return BadRequest(new { message = "Username or password is incorrect" });
            }

            var tokenHandler = new JwtSecurityTokenHandler();
            var tokenKey = Encoding.UTF8.GetBytes(_configuration["JWT:Key"]);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(ClaimTypes.Name, model.Username)
                }),
                Expires = DateTime.UtcNow.AddMinutes(60),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(tokenKey), SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            string tokenString = tokenHandler.WriteToken(token);

            return Ok(new { Token = tokenString });
        }

    }

    public partial class LoginModel
    {
        public string Username { get; set; }
        public string Password { get; set; }
    }
}

This code handles user authentication and generates a JWT. It uses the JwtSecurityTokenHandler class to generate the token, and sets the token’s expiration time to 7 minutes from the current time. It also uses the app settings to set the secret key used to sign the token.

Here we are not connecting to the database just to keep it simple. Instead created list and stored sample user data.

namespace JWT.MyTechnicalSkills
{
    public interface IUserService
    {
        User Authenticate(string Username, string Password);

        User GetById(int Id);
    }

    public class UserService : IUserService
    {
        public List<User> Users = new List<User>();
        public UserService()
        {
            Users.Add(new User() { Id = 1, Username = "MyTechnicalSkills", Password = "MyTechnicalSkills" });
        }

        public User Authenticate(string Username, string Password)
        {
            var user = Users.FirstOrDefault(x => x.Username == Username && x.Password == Password);
            return user;
        }

        public User GetById(int Id)
        {
            var user = Users.FirstOrDefault(x => x.Id == Id);
            return user;
        }
    }

    public partial class User
    {
        public int Id { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
    }
}
Step 6: Protect API endpoints

You will need to protect your API endpoints by requiring a valid JWT to be included with each request. You can do this using the [Authorize] attribute on your controller methods. Here is an example:

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace JWT.MyTechnicalSkills.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [Authorize]
    public class UsersController : ControllerBase
    {
        private readonly IUserService _userService;

        public UsersController(IUserService userService)
        {
            _userService = userService;
        }

        [HttpGet]
        public IActionResult Get(int UserId)
        {
            var user = _userService.GetById(UserId);
            if (user == null)
            {
                return NotFound();
            }

            return Ok(user);

        }
    }
}

This code gets the user ID from the JWT and uses it to retrieve the user’s information. The [Authorize] attribute requires that a valid JWT be included with the request, otherwise the request will be rejected with a 401 Unauthorized status code.

Step 7: Test the APIs

Step 1: Launch your preferred API testing tool or software. Create a new request for the API endpoint that requires authentication. I’m using the Postman here.

Provide the following deatils and click on the “Send” button on the right.

Type: POST
URL: https://localhost:7173/api/Authentication

Body:
{
  "username": "MyTechnicalSkills",
  "password": "MyTechnicalSkills"
}
Test the API in Postman 1

Step 2: Lets call the user detail API which is protected by JWT. Provide the following details in Postman.

Type: GET
URL: https://localhost:7173/api/Users?UserId=1
Token: <add token that we got on step 1> example: "eyJhbGciOiJIUzI1NiIsInR..."
Test the API in Postman 2

We got the 200 OK status and the user object from our API.


Add Swagger Authentication and Improve API Documentation

Swagger is a popular tool for documenting web APIs. It allows you to generate interactive API documentation. Which makes it easy for developers to understand how to use your API. Let integrate Swagger Authentication into a .NET Web API with token-based authentication.

Step 1: Install the necessary packages

To use Swagger with your .NET 6 web API, you will need to install the Swashbuckle.AspNetCore NuGet package. This package provides middleware that can generate Swagger documentation.

dotnet add package Swashbuckle.AspNetCore
Step 2: Configure Swagger in Program.cs

In the Program.cs file, you will need to configure Swagger. Here is an example configuration:

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.Text;

namespace JWT.MyTechnicalSkills
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // builder.Services.AddAuthentication();

            // Add services to the container.
            builder.Services.AddTransient<IUserService, UserService>();

            builder.Services.AddControllers();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    In = ParameterLocation.Header,
                    Description = "Please insert JWT with `Bearer` into field. Example: `Bearer eXterwe012yt...`",
                    Name = "Authorization",
                    Type = SecuritySchemeType.ApiKey,
                });
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            }
                        },
                        Array.Empty<string>()
                    }
                });
            }); ;

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();

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

            app.MapControllers();

            app.Run();
        }
    }
}

This code configures Swagger to generate documentation for your API. It also sets up the JWT authentication C# scheme, and adds a security definition for the Bearer token scheme.

If you want to customize the Swagger UI further, you can follow a step-by-step guide on “How to Add Swagger to Web API .NET 7

Step 3: Test the APIs with Swagger UI

Run the application. Visite the https://localhost:7173/swagger/index.html to see Swagger UI.

Test the APIs with Swagger UI

Also, You can generate Swagger documentation by running your API and visiting the /swagger/v1/swagger.json URL in your web browser. This will generate a JSON file that describes your API, which can be used by tools like Swagger UI to generate interactive documentation.


How to validate token yourself?

For any reason if you want to validate token by yourself. Here is the good example to do that exactly.

using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Principal;
using System.Text;

namespace JWT.MyTechnicalSkills
{
    public class Class
    {
        static string key = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090f";

        static void Main(string[] args)
        {
            string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6.....[Token]";
            var isValidToken = ValidateToken(token);
            Console.WriteLine($"Is valid token? {isValidToken}");
        }

        private static bool ValidateToken(string authToken)
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var validationParameters = GetValidationParameters();

            SecurityToken validatedToken;
            IPrincipal principal = tokenHandler.ValidateToken(authToken, validationParameters, out validatedToken);
            return true;
        }

        private static TokenValidationParameters GetValidationParameters()
        {
            return new TokenValidationParameters()
            {
                ValidateLifetime = false, // Because there is no expiration in the generated token
                ValidateAudience = false, // Because there is no audiance in the generated token
                ValidateIssuer = false,   // Because there is no issuer in the generated token
                ValidIssuer = "Sample",
                ValidAudience = "Sample",
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)) // The same key as the one that generate the token
            };
        }
    }
}

Conclusion

JWT authentication is a popular and secure way to authenticate and secure web APIs and microservices. With the release of .NET 7, implementing JWT authentication C# in your web APIs has become even easier.

By following the steps outlined in this article, you can quickly and easily add JWT authentication to your .NET 7 web APIs. The use of JWT tokens offers several benefits, including increased security and reduced network overhead.

With the added convenience of using Swagger documentation, developers can easily test and document their APIs. And making the development process faster and more efficient.

Overall, implementing JWT authentication C# in your .NET 7 web APIs is a crucial step in securing your application and protecting your user’s data. With the detailed guide provided in this article, you can easily implement this important security measure in your .NET 7 web API.

Thank you for reading, and happy coding!

Leave a Comment