Understanding Token Based Authentication in ASP.NET Core 3.1 using JSON WEB TOKENS

In this post we will discuss the Token Based Authentication in ASP.NET Core 3.1.  Security is one of the backbone for modern web application development. In most of the Modern Web Applications the security is implemented using JSON Web Tokens. 

What is JSON Web Token?
JSON Web Token (JWT), is an open standard, self-defined and compact mechanism for securely transmitting information across parties using JSON object. Since the token carries digital signature, the information in transmission is verified and trusted. The signature can be generated using HMAC algorithm or using public/private key pairs using RSA. The Signed token can be used to verify integrity of claims contained within it. The claim are the entities contained in the token e.g. user, roles, etc.

When can we use JSON Web Tokens?
We can use JSON Web Tokens in case of following scenarios

  • Authorization:  This is the frequent scenario of using JWT in modern applications. When the user login in the application, the JWT is issued and then this token can be used by the user for subsequent requests. Each request contains the token and the application will provide access of the services, routes, views, etc to the user based on the validity of the token.
  • Exchanging Information: Using JWT the best way for transmitting data across parties securely. The Key pair is the major role player to make sure that the senders are authorized senders.

JSON Web Token Structure

The JSON Web Token has following three sections
  • Header
  • Payload
  • Signature
The Header consist of two parts the first is JWT and the second is the signing algorithm that is used. The Payload contains claims. Claims are the statements about the entity e.g. Users, roles, etc. The Signature is used to verify an integrity of the message.

Using JSON Web Token to Secure WEB API in ASP.NET Core 3.1
In the next steps we will go through the complete implementation of the JWT in ASP.NET Core. We will use ASP.NET Core Identity Packages. We will also use Entity Framework Core (EF Core) to generate the database that will store tables for managing application security by storing User information in it. The following figure explains the working of Token Based security in ASP.NET Core

Figure 1: The JWT working in ASP.NET Core 3.1     

The above diagram explains the JSON Web Token in ASP.NET Core 3.1 as explained in following points
  1. The client application will make request to ASP.NET Core by sending Credentials.
  2. The ASP.NET Core Identity APIs will verify the request with credentials for Authentication.
  3. The verification process will start by reading credentials
  4. The Auth Request will use the authentication infrastructure e.g. Database to verify the authentication.
  5. The database will be accessed to check the User Name and Password
  6. The credentials verification will be divided into two sections 
    1. If the Auth. Request fails to verify credentials then response will be send back to client as No Authentication e.g. 401 error code
    2. If the Auth Request successfully verifies credentials, the Token will be generated with Signature and algorithm and it will be send back to the client application.
  7. The client application will use this token to make the request to the ASP.NET Core application.
  8. The ASP.NET Core application will verify the token for integrity and Authorization.
  9. If the Token is valid then the success response will be sent to the client, else the Un-Authorized response will be sent to the client.
To implement steps in this article following softwares must be installed on your machine
  1. If using Windows OS e.f. Windows 10, then install Microsoft Visual Studio 2019 (Community Edition/Enterprise/Professional edition). The community edition can be downloaded from the this link . Please install latest update.
  2. Install .NET Core 3.1 SDK from this link.
  3. You can also use Microsoft Visual Studio Code (VSCode), It can be downloaded from this link. (If you are using OS other than Windows e.g. Linux or MAC the VS Code is the best IDE.)
Note: I have used Visual Studio 2019 for the coding. If you want to use VS-Code then use dotnet CLI to create project.

Step 1: Open Visual Studio 2019 and create a new ASP.NET Core Web Application as shown in the following figure

Figure 2: Creating a new ASP.NET Core Web Application 
    

Click on Next button, the new window will be displayed, provide the name of the application as ASPNETCORE31_JWT and click on Create button. The new window will be displayed, select API and select framework as ASP.NET Core 3.1 as shown in the following figure

Figure 3: ASP.NET Core API application         

Step 2: Since we will be using ASP.NET Core Identity to store User information in the database we need to make use of Entity Framework Core and Identity Core packages. Install packages in the project as shown in the following figure



Figure 4: List of packages to be installed in the project 

(Note: The diagram shows packages after installation). We need packages for JWT, Identity and EF Core as mandatory packages.

Step 3: Modify appsettings.json file to define connection string for connecting the security database and database for storing application data as shown in the following code
"ConnectionStrings": {
"DataAppContextConnection":"Server=(localdb)\\mssqllocaldb;Database=AppDb;Trusted_Connection=True;MultipleActiveResultSets=true",
"SecurityDbContextConnection":"Server=(localdb)\\mssqllocaldb;Database=AppSecurityDB;Trusted_Connection=True;MultipleActiveResultSets=true"
}
Listing 1: Connection string in appsettings.json 
We will be using AppDb for storing application data and AppSecurityDB will be used to store the security information like Users.

Step 4: In the application add a new folder and name it as Models. In this folder add a new class file and name it as SecurityDbContext.cs. Add the following code in this file as shown in the following listing
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace ASPNERCore31_JWT.Models
{
    public class SecurityDbContext : IdentityDbContext
    {
        public SecurityDbContext(DbContextOptions<SecurityDbContext> options):base(options)
        {
        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
        }
    }
}

Listing 2: The SecurityDbContext class 
The SecurityDbContext class is derived from IdentityDbContext, this class is used to manage Database connection where application users are stored in table. 
In the Models folder add a new class name as UserModel.cs. In this class file add code as shown in the following listing
using System.ComponentModel.DataAnnotations;

namespace ASPNERCore31_JWT.Models
{

    public class LoginUser
    {
        [Required(ErrorMessage ="User Name is Must")]
        public string UserName { get; set; }

        [Required(ErrorMessage = "Password is Must")]
        public string Password { get; set; }
    }

    public class RegisterUser
    {
        [Required(ErrorMessage = "Email is Must")] 
        [EmailAddress]
        public string Email { get; set; }
        [Required(ErrorMessage = "Password is Must")]
        [RegularExpression("^((?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])|(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[^a-zA-Z0-9])|(?=.*?[A-Z])(?=.*?[0-9])(?=.*?[^a-zA-Z0-9])|(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^a-zA-Z0-9])).{8,}$", 
            ErrorMessage = "Passwords must be minimum 8 characters and must be string password with uppercase character, number and sepcial character")]
        public string  Password { get; set; }
        [Compare("Password")]
        public string ConfirmPassword { get; set; }
    }
}

Listing 3: LoginUser and RegisterUser classes
The RegisterUser class contain properties for registering users with Email, password and confirm password. The LoginUser class contain properties for accepting login information like UserName and Password.
In the Models folder add a new class file name it as Product.cs. Add the code as shown in the following listing
using System.ComponentModel.DataAnnotations;
namespace ASPNERCore31_JWT.Models
{
    public class Product
    {
        [Key]
        public int ProductRowId { get; set; }
        [Required(ErrorMessage ="Product Name is required")]
        public string ProductName { get; set; }
        [Required(ErrorMessage = "Product Price is required")]
        public int Price { get; set; }
    }
}

Listing 4: The code for Product Entity class
In the Models folder add a new class file and name it as MyAppDbContext.cs. In this file add the code as shown in the following listing
using Microsoft.EntityFrameworkCore;

namespace ASPNERCore31_JWT.Models
{
    public class MyAppDbContext : DbContext
    {
        public DbSet<Product> Products { get; set; }
        public MyAppDbContext(DbContextOptions<MyAppDbContext> options):base(options)
        {
        }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }
    
}

Listing 5: The MyAppDbContext class
The code in the above listing contains the MyAppDbContext class derived from DbContext class. This class will be used to connect to the database that contains Product table for performing CRUD operations with Product Table. 
We will also add a new class to format response from the APIs. Add a new class in the Models folder and name it as ResponseData.cs. Add the code in this file as shown in the following listing
namespace ASPNERCore31_JWT.Models
{
    public class ResponseData
    {
        public string Message { get; set; }
    }
}

Listing 6: The ResponseData class  

Step 5: To generate databases using Entity Framework Core using Code first approach run following commands from the command prompt. Open the command prompt and navigate to the project folder. Run the following command to generate migrations and update database

dotnet ef migrations add InitialCreate -c ASPNERCore31_JWT.Models.SecurityDbContext

The above command will generate the Migration files for Security database. Run the following command to create/update database

dotnet ef database update  -c ASPNERCore31_JWT.Models.SecurityDbContext


The above command will create a new database of name AppSecurityDb with various Identity Tables in it e.g. AspNetUsers, AspNetRoles 

Run the following command to generate migrations for Application data and create/update database

dotnet ef migrations add InitialCreate -c ASPNERCore31_JWT.Models.MyAppDbContext

dotnet ef database update  -c ASPNERCore31_JWT.Models.MyAppDbContext

The above command will create a new Add AppDb Database with Products table in it.

Step 6: In Visual Studio 2019, connect to the database using Server Explorer and add some records in the Products table.
   
Step 7: Modify the appsettings.json file to define secret key and expiry time for the token as shown in the following listing

 "JWTCoreSettings": {
    "SecretKey": "f4LZOS1MJ+lwLI+NZDSatxQffwf4CMnCUyAJaEcd/tm5tcLhXkuV9bO+bYF+NgdmrJqE69LDDiQotz0rQIfJqw==",
    "ExpiryInMinuts": 20
  }

Listing 7: The JSON Web Token Secret Key and Expiry time. 

Note that the Secret Key is generated using RNGCryptoServiceProvider class. I have created a separate .NET Core console application to generate the key. The code I have used is shown in the following listing
using System;
using System.Security.Cryptography;

namespace Core_JWTKey_Generator
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var rNGCryptoServiceProvider = new RNGCryptoServiceProvider())
            {
                var SigningSecretKey = new byte[64];
                rNGCryptoServiceProvider.GetBytes(SigningSecretKey);
                Console.WriteLine($"Secret Key is {Convert.ToBase64String(SigningSecretKey)}");
            }
            Console.ReadLine();
        }
    }
}

Listing 8: The Secret Key generation code


Step 8: In the project add a new folder and name it as Services. In this folder add a new class and name it as AuthenticationService.cs. Add code in this class file as shown in the following listing
using ASPNERCore31_JWT.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Threading.Tasks;


namespace ASPNERCore31_JWT.Services
{
    /// <summary>
    /// The followint class is used for the following
    /// 1. The class will accept Login Details and then Issue the token based on the login Status
    /// 
    /// </summary>
    public class CoreAuthService
    {
        IConfiguration configuration;
        SignInManager<IdentityUser> signInManager;
        UserManager<IdentityUser> userManager;
        /// <summary>
        /// 1.
        /// </summary>
        /// <param name="configuration"></param>
        /// <param name="signInManager"></param>
        /// <param name="userManager"></param>
        public CoreAuthService(IConfiguration configuration, 
            SignInManager<IdentityUser> signInManager,
            UserManager<IdentityUser> userManager)
        {
            this.configuration = configuration;
            this.signInManager = signInManager;
            this.userManager = userManager;
        }
        
        /// <summary>
        /// 2.
        /// </summary>
        /// <param name="register"></param>
        /// <returns></returns>
        public async Task<bool> RegisterUserAsync(RegisterUser register)
        {
            bool IsCreated = false;
            var registerUser = new IdentityUser() { UserName = register.Email, Email = register.Email };
            // 2a.
            var result = await userManager.CreateAsync(registerUser, register.Password);
            if (result.Succeeded)
            {
                IsCreated = true;
            }
            return IsCreated;
        }
        /// <summary>
        /// 3.
        /// </summary>
        /// <param name="inputModel"></param>
        /// <returns></returns>
        public async Task<string> AuthenticateUserAsync(LoginUser inputModel)
        {
            
            string jwtToken ="";
           
            // 3a.
           var result =  await signInManager.PasswordSignInAsync(inputModel.UserName, inputModel.Password, false, lockoutOnFailure: true);
            if (result.Succeeded)
            {
                //3b Read the secret key and the expiration from the configuration 
                var secretKey = Convert.FromBase64String(configuration["JWTCoreSettings:SecretKey"]);
                var expiryTimeSpan = Convert.ToInt32(configuration["JWTCoreSettings:ExpiryInMinuts"]);
                //3c. logic to get the user role
                // get the user object based on Email
                
                IdentityUser user = new IdentityUser(inputModel.UserName);

                //3d set the expiry, subject, etc.
                // note that Issuer and Audience will be null because 
                // there is no third-party issuer
                var securityTokenDescription = new SecurityTokenDescriptor()
                {
                    Issuer = null,
                    Audience = null,
                    Subject = new ClaimsIdentity(new List<Claim> {
                        new Claim("username",user.Id,ToString()),
                    }),
                    Expires = DateTime.UtcNow.AddMinutes(expiryTimeSpan),
                    IssuedAt = DateTime.UtcNow,
                    NotBefore = DateTime.UtcNow,
                    SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(secretKey), SecurityAlgorithms.HmacSha256Signature)
                };
                //3e Now generate token using JwtSecurityTokenHandler
                var jwtHandler = new JwtSecurityTokenHandler();
                var jwToken = jwtHandler.CreateJwtSecurityToken(securityTokenDescription);
                jwtToken = jwtHandler.WriteToken(jwToken);
            }
            else
            {
                jwtToken =  "Login failed"; 
            }

            return jwtToken;
        }
    }
}

Listing 9: The code for registering user and authenticating user generating JSON Wen Token

The above code have following specifications

  1. Following interface and classes are injected in the constructor of the class
    1. IConfiguration, interface will be used to read key/value pairs from the appsettings.json file. This file contains connection strings and JSON Web Token Settings.
    2. The SignInManager<IdentityUser> class will be used to provide API for user sign-in.  The IdentityUser class is used to define user properties e.g. Email, Password, etc. The SignInManager class provides PasswordSignInAsync() method to sign-in user.
    3. The  UserManager<IdentityUser> class is used to provide APIs for managing users stored in the persistent store like database. This class provides CreateAsync() method to create new user.
  2. The method RegisterUserAsync() method accepts RegisterUser object as an input parameter. This method stores data from RegisterUser object in IdentityUser object and pass the IdentityUser object to the CreateAsync() method to register new user for the application.
  3. The AuthenticateUserAsync() method accepts LoginUser  object as input parameter. This object contains UserName and Password. The AuthenticateUserAsync() method will use this UserName and Password to sign-in using PasswordSignInAsync() method of the SignInManager class. The method performs following once the  
    1. If the the user login is  successful then this method uses IConfiguration interface to read Secret Key and Expiry from asspsettings.json file. 
    2. Further this method uses SecurityTokenDescriptor class. This class defines all parameters those are required for issued token.  The most important here is the Subject information. The issue token will store username in claim in subject information. The SignInCredentials uses secret key and SecurityAlgorithms.HmacSha256Signature for generating digital signature. This signature will be used by token generator. 
    3. Further method uses JwtSecurityTokenHandler() class. This class will generate and validate the JSON Web Token based on the security description and then using WriteToken() method and then serialize the token into JWT compact serialization format as explain in JSON Web Token Structure section.
Step 9: In the Services folder add a new interface file and name it as IRepository.cs. Add the following code in this file as shown in the following listing
using System.Collections.Generic;

namespace ASPNERCore31_JWT.Services
{
    public interface IRepository<TEntity,in TPk>
    {
        IEnumerable<TEntity> Get();
        TEntity Get(int id);
        TEntity Create(TEntity entity);
    }
}

Listing 11: Repository interface
The above code is the repository interface that contains generic methods for create and read operations.
In the  Services folder add a new class file and name it as ProductRepository.cs. Add the code in this class file as shown following listing
using ASPNERCore31_JWT.Models;
using System.Collections.Generic;
using System.Linq;

namespace ASPNERCore31_JWT.Services
{
    public class ProductRepository : IRepository<Product, int>
    {
        MyAppDbContext ctx;
        public ProductRepository(MyAppDbContext ctx)
        {
            this.ctx = ctx;
        }
        public Product Create(Product entity)
        {
            ctx.Products.Add(entity);
            ctx.SaveChanges();
            return entity;
        }

        public IEnumerable<Product> Get()
        {
            return ctx.Products.ToList();
        }

        public Product Get(int id)
        {
            return ctx.Products.Find(id);
        }
    }
}

Listing 12: The Product Repository class 
The above code performs Read/Write operations for the Products in the database.
Step 10: Modify the ConfigureServices() method of the Startup.cs.  In this method add the code as shown in the following listing

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddControllersWithViews();
            // 1.
            services.AddDbContext<SecurityDbContext>(options =>
            {
                options.UseSqlServer(Configuration.GetConnectionString("SecurityDbContextConnection"));
            });

            //2.
            services.AddDefaultIdentity<IdentityUser>(
                options => options.SignIn.RequireConfirmedAccount = false)
                .AddEntityFrameworkStores<SecurityDbContext>();
            // 3.
            services.AddDbContext<MyAppDbContext>(options => {
                options.UseSqlServer(Configuration.GetConnectionString("DataAppContextConnection"));
            });
            // 4.
            services.AddScoped<CoreAuthService>();

            // 5.
        byte[] secretKey = Convert.FromBase64String(Configuration["JWTCoreSettings:SecretKey"]);

            // 6.
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
         x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(secretKey),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });

            // 7.
            services.AddScoped<IRepository<Product,int>, ProductRepository>();
         
        }
Listing 13: The ConfigureServices() method to register Repositories, DbContext and Identity
The above code has following specifications (Note that the following line numbers matches with comment number applied on the code)

  1. The registration of the SecurityDbContext by reading SecurityDbContextConnection string from appsettings.json
  2. Add the default identity to add common identity services for the application. These service includes default UI for Login, register User, etc views, Token providers, etc. 
  3. Register MyAppDbContext in the dependency container.
  4. Register CoreAuthService in dependency container. This class contains methods for registering users and authenticating users.
  5. Read the secret key from the appsettings.json
  6. This is the most important part of the configuration. Here we are defining the JWT Authentication scheme, so that JSON Web Token must be passed by the end-user for authentication. The AddJwtBearer() extension method defines various configuration parameters for validating token.
  7. This step register ProductRepository in dependency container.
Step 11: Modify the Configure() method of the Startup.cs to add Authentication and Authorization middleware. Add the code as shown in the following listing
......................
            app.UseAuthentication();
            app.UseAuthorization();
.....................
Listing 14: The Authorization and Authentication Middleware

These middlewares makes sure that the HttpRequest should contain credentials (UserName/Password) for authentication and token for authorization. 

Step 12: In the Controllers folder add a new empty API controller and name it as AuthController. This controller will contain methods for registering the new user and authenticating users. Add the code in the controller as shown in the following listing
using ASPNERCore31_JWT.Models;
using ASPNERCore31_JWT.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

namespace ASPNERCore31_JWT.Controllers
{
    [Route("api/[controller]/[action]")]
    [AllowAnonymous]
    [ApiController]
    public class AuthController : ControllerBase
    {
        CoreAuthService authenticationService;
        public AuthController(CoreAuthService authenticationService)
        {
            this.authenticationService = authenticationService;
        }


        [HttpPost]
        public  async Task<IActionResult> Register(RegisterUser user)
        {
            if (ModelState.IsValid)
            {
                var IsCreated = await authenticationService.RegisterUserAsync(user);
                if (IsCreated == false)
                {
                    return Conflict("The User Already Present");
                }
                var ResponseData = new ResponseData()
                {
                     Message = $"{user.Email} User Created Successfully"
                };
                return Ok(ResponseData);
            }
            return BadRequest(ModelState);
        }

        [HttpPost]
        public async Task<IActionResult> Login(LoginUser inputModel)
        {
            if (ModelState.IsValid)
            {
                var token = await authenticationService.AuthenticateUserAsync(inputModel);
                if (token == null)
                {
                    return Unauthorized("The Authentication Failed");
                }
                var ResponseData = new ResponseData()
                {
                    Message = token
                };

                return Ok(ResponseData);
            }
            return BadRequest(ModelState);
        }


    }
}
Listing 15: The AuthController class
The above controller is constructor injected with CoreAuthService class. The Register() and Login() are HttpPost methods invokes RegisterUserAsync() and AuthenticateUserAsync() methods from CoreAuthService class.

Step 13: In the Controllers folder add a new empty API controller and name it as ProductsController. In this controller add the code as shown in the following listing
using ASPNERCore31_JWT.Models;
using ASPNERCore31_JWT.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace ASPNERCore31_JWT.Controllers
{
    [Route("api/[controller]")]
    [Authorize]
    [ApiController]
    public class ProductsController : ControllerBase
    {
        IRepository<Product, int> repository;
        public ProductsController(IRepository<Product, int> repository)
        {
            this.repository = repository;
        }

        [HttpGet]
        public IActionResult Index()
        {
            var prds = repository.Get();
            return Ok(prds);
        }

        [HttpPost]Authorize
   
        public IActionResult Post(Product product)
        {
            if (ModelState.IsValid)
            {
                repository.Create(product);
                return Ok(product);
            }
            return BadRequest(ModelState);
        }
    }
}
Listing 16: The ProductsController class
The ProductsController class has Authorize attribute applied on it. This means that to access methods from ProductsController the user must be authenticated and authorized. The ProductsController class is constructor injected with ProductsRepository class using IRepository interface. The ProductsController  class invokes methods from ProductRepository class.

Build the application and make sure that its error free. Run the application as shown in the following image

Figure 5: Running the application

This will run the application on port 5000. The application will run with URL as http://localhost:5000.

To test the application use the I have used Advanced REST client. This can be downloaded from this link.

Open the Advanced REST Client and enter following details to register user
Method: Post
URL: http://localhost:5000/api/Auth/Register
Headers: Content-Type: application/json
Body: {
  "Email":"a.b@msit.com",
  "Password":"P@ssw0rd_",
  "ConfirmPassword": "P@ssw0rd_"
}
The following figure shows the POST request

Figure 6: The Post request to create new user
Click on the SEND button. This will make post request to register new user. The result will be displayed as shown in the following figure

Figure 7: The user created successfully
Make a new POST request to login/authenticate user using Advanced REST Client by entering following details

Method: Post
URL: http://localhost:5000/api/Auth/Login
Headers: Content-Type: application/json
Body:{
  "UserName": "a.b@msit.com",
  "Password": "P@ssw0rd_"
}
The following figure shows the POST request

Figure 8: The Post request to authenticate user
Click on SEND button, the user will be authenticated successfully, the token will be responded in response as shown in the following figure

Figure 9: The Token response

Make the GET request to receive products data as shown in the following details

Method: Get
URL: http://localhost:5000/api/Products
Headers: Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImY2MzIyMTgyLWNlYjQtNDFlZS1hOGFhLTYxYTg0MzkxZDUxZCIsIm5iZiI6MTU3ODA1NDAwMiwiZXhwIjoxNTc4MDU1MjAyLCJpYXQiOjE1NzgwNTQwMDJ9.98ws395CglVR0LEhP4ZmJKSScAmYVDmeZEXX5voYo2Y

The following figure shows the the Get request

Figure 10: The Get request
Click on the SEND button, the Products data will be responded as shown in the following figure

Figure 11: The Product response

Thats it. The complete code of the article can be downloaded from this link.

Conclusion: The JSON Web Token security is the most commonly followed standard for modern application development. The Payload part of the Token contains claims that is used to authorize the user. We can use JSON Web tokens to authorize any client application like .NET Desktop clients, Web Clients, and JavaScript client applications. 

Popular posts from this blog

Uploading Excel File to ASP.NET Core 6 application to save data from Excel to SQL Server Database

ASP.NET Core 6: Downloading Files from the Server

ASP.NET Core 6: Using Entity Framework Core with Oracle Database with Code-First Approach