What are we going to learn ?
  • Why do we need token in RESTful APIs ?
  • What is JWT ?
  • How to generate JWT ?
  • How to Validate it ?

Why do we need token in RESTful APIs ?

Tokens serve as a fundamental mechanism for authentication and authorization in RESTful APIs. They provide a way to verify the identity of users and grant them access to specific resources without the need to transmit sensitive information, such as usernames and passwords, with every request. Let’s explore the reasons why tokens are essential and the differences between custom tokens and JWT.

  • Statelessness: RESTful APIs are designed to be stateless, meaning that each request from a client must contain all the information needed to understand and process the request. Tokens allow the server to authenticate users without maintaining session state on the server side.
  • Security: By using tokens, sensitive information is not exposed in every request. Instead, a token can be used to represent the user's identity securely. This reduces the risk of credential theft.
  • Scalability: Tokens enable horizontal scaling of applications. Since the server does not need to store session information, multiple instances of the server can handle requests independently, improving load balancing and performance.
  • Cross-Domain Access: Tokens facilitate cross-domain requests, which is particularly useful in microservices architectures where different services may reside on different domains.
  • Expiration and Revocation: Tokens can be designed to expire after a certain period, enhancing security. Additionally, they can be revoked if a user logs out or if suspicious activity is detected.
What is JWT ?

JWT, or JSON Web Token, is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.

Structure of JWT
A JWT is composed of three parts, each separated by a dot (.):

1- Header: This 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.
{
    "alg": "HS256",
    "typ": "JWT"
  }
 

2- Payload: This contains the claims. Claims are statements about an entity (typically, the user) and additional data. There are three types of claims:

  • Registered claims: Predefined claims that are not mandatory but recommended, such as iss (issuer), exp (expiration time), and sub (subject).
  • Public claims: Custom claims that can be defined at will by those using JWTs.
  • Private claims: Custom claims created to share information between parties that agree on using them.
    {
        "sub": "1234567890",
        "name": "John Doe",
        "admin": true,
        "iat": 1516239022
    }
 

3- Signature: To create the signature part, you take the encoded header, the encoded payload, a secret, and the algorithm specified in the header. For example, if you are using the HMAC SHA256 algorithm, the signature will be created as follows:

    HMACSHA256(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    your-256-bit-secret
    )
   

Need Assembly to Use JWT in ASP.NET Core
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

How to generate JWT ?
 - : I have created a "Authentication" controller and Method "Login"
I have a List of User , Where UserName and Password , requested UserName and Password will match to User List . If UserName and Password will match then User Authenticated and JWT will generate.
Otherwise will be unauthorized. 

(Here I have static UserName and password , you can make your own login to validate these Username and Password from the database)

Need to add key in appsettings.json file :

    "JWT": {
        "Key": "thisissecretkeythisissecretkeythisissecretkeythisissecretkeythisissecretkeythisissecretkey",
        "Issuer": "http://localhost:51947",
        "Audience": "http://localhost:51947"
    }

Need to add JWT Authentication in Program.cs file :
added JWT Authentication Code :
    //JWT Authentication Start
    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["JWT:Issuer"],
            ValidAudience = builder.Configuration["JWT:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:Key"]))
        };
    });
    // JWT Authentication End

Full Program.cs file


    using Microsoft.AspNetCore.Authentication.JwtBearer;
    using Microsoft.IdentityModel.Tokens;
    using Microsoft.AspNetCore.Localization;
    using Microsoft.AspNetCore.Mvc.Razor;
    using System.Globalization;
    using System.Text;

    var builder = WebApplication.CreateBuilder(args);

    ConfigurationManager configuration = builder.Configuration;
    builder.Services.AddControllers();
    builder = new CRUD_WEB_API.InjectDependency().InjectDepency(builder);
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();

    //JWT Authentication Start
    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = builder.Configuration["JWT:Issuer"],
            ValidAudience = builder.Configuration["JWT:Audience"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:Key"]))
        };
    });
    // JWT Authentication End
    builder.Services.AddControllersWithViews()
            .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
            .AddDataAnnotationsLocalization();

    var app = builder.Build();
    if (app.Environment.IsDevelopment())
    {
        app.UseSwagger();
        app.UseSwaggerUI();
    }

    app.UseHttpsRedirection();
    app.UseAuthentication();
    app.UseAuthorization();
    app.MapControllers();
    app.Run();


Note : Make Sure of sequence of method to be as below :

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

Authentication Controller : Login Method :- 

using System.Data;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using CRUD_WEB_API.Model;
using CRUD_WEB_API.ServiceLayer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;

namespace CRUD_WEB_API.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    [AllowAnonymous]
    public class Authentication : ControllerBase
    {
        private readonly ICRUDOperationSL _ICRUDOperationSL;
        private readonly IConfiguration configuration;
        public Authentication(ICRUDOperationSL iCRUDOperationSL, IConfiguration _configuration)
        {
            this._ICRUDOperationSL = iCRUDOperationSL;
            this.configuration = _configuration;
        }
        [HttpPost]
        [Route("Login")]
        public async Task<IActionResult> Login([FromBody] Login req)
        {
            string WToken = "";
            try
            {
                List<User> users = new List<User>
                {
                    new User { UserName = "Admin", Password = "Admin@123" },
                    new User { UserName = "Surya", Password = "Surya@123" },
                };
                bool userExists = users.Exists(u => u.UserName == req.userName && u.Password == req.password);
                if (userExists)
                {
                    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JWT:Key"]));
                    var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
                    var claims = new[]
                    {
                        new Claim("userName",req.userName),
                        new Claim("UserProfile","Admin")
                        };
                    var token = new JwtSecurityToken(configuration["JWT:Issuer"],
                        configuration["JWT:Audience"],
                        claims,
                        expires: DateTime.Now.AddMinutes(15),
                        signingCredentials: credentials);

                    WToken = new JwtSecurityTokenHandler().WriteToken(token);
                    return Ok(new { token = WToken });
                }
                return Unauthorized(new
                {
                    error = new
                    {
                        message = "Authentication failed. Please check your username and password.",
                        code = "AUTH_FAILED"
                    }
                });
            }
            catch (Exception)
            {
                return StatusCode(500, new { ErrorCode = 500, error = "Something Went Wrong" });
            }
        }
    }
}



When I call Login API's through postman then , get below JWT token :



When Enter wrong UserName or Password it will generate below response :


Every API's end Point , you have to make it secure Just Use Authorize attribute to your controller :(if using before controller class : then every end point's of that controller will be secured via JWT.)



Now I have Home controller and , Need to get Employee Data using JWT token :

    [HttpGet("GetEmployee")]
    public async Task<IActionResult> GetEmployee()
    {
        var employees = new[]
        {
            new
            {
                id = 1,
                firstName = "John",
                lastName = "Doe",
                email = "john.doe@example.com",
                position = "Software Engineer"
            },
            new
            {
                id = 2,
                firstName = "Jane",
                lastName = "Smith",
                email = "jane.smith@example.com",
                position = "Project Manager"
            }
        };

        return Ok(new { employees});
    }

If I will not pass correct or expired JWT then it's response will be Unauthorized with 401 status code :


 with correct JWT :

Hope you have understood  about JWT : How to Generate and Validate in ASP.NET CORE
Thanks 

Leave a Reply

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


Talk to us?

Post your blog

F.A.Q

Frequently Asked Questions