How to use Web API JWT Token

This post shows you how to generate jwt token in asp.net core using c# code.

We need to create an asp.net core project, then install package "Microsoft.AspNetCore.Authentication.JwtBearer" from Nuget Manage Packages in your visual studio.

To play the demo asp.net core authentication, we will create Account, AccountInMemory classes.

Account.cs

namespace ASPNET.Models
{
    public class Account
    {
        public string Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }
    }
}

AccountInMemory.cs

namespace ASPNET.Models
{
    using System;
    using System.Collections.Generic;

    public static class AccountInMemory
    {
        public static IList<Account> ArrayAccount = new List<Account>();

        static AccountInMemory()
        {
            ArrayAccount.Add(new Account
            {
                Id = Guid.NewGuid().ToString("n"),
                FirstName = "Lucy",
                LastName = "Hynh",
                UserName ="admin",
                Password = "123abc"
            });
        }
    }
}

Create a new folder with name is Provider, then create TokenProviderOptions, TokenProviderMiddleware classes to your Provider folder.

TokenProviderOptions.cs

namespace ASPNET.Provider
{
    using Microsoft.IdentityModel.Tokens;
    using System;

    public class TokenProviderOptions
    {
        public string Path { get; set; } = "/token";

        public TimeSpan Expiration { get; set; } = TimeSpan.FromDays(+1);

        public SigningCredentials SigningCredentials { get; set; }
    }
}

TokenProviderMiddleware.cs

namespace ASPNET.Provider
{
    using ASPNET.Models;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Options;
    using Newtonsoft.Json;
    using System;
    using System.IdentityModel.Tokens.Jwt;
    using System.Security.Claims;
    using System.Threading.Tasks;
    using System.Linq;
    using System.Collections.Generic;

    public class TokenProviderMiddleware
    {
        private readonly RequestDelegate _next;

        private readonly TokenProviderOptions _options;

        public TokenProviderMiddleware(
            RequestDelegate next,
            IOptions<TokenProviderOptions> options)
        {
            _next = next;
            _options = options.Value;
        }

        public Task Invoke(HttpContext context)
        {
            if (!context.Request.Path.Equals(_options.Path, StringComparison.Ordinal))
            {
                return _next(context);
            }

            if (!context.Request.Method.Equals("POST")
               || !context.Request.HasFormContentType)
            {
                context.Response.StatusCode = 400;
                return context.Response.WriteAsync("Bad request.");
            }

            return GenerateToken(context);
        }

        private async Task GenerateToken(HttpContext context)
        {
            var username = context.Request.Form["username"];
            var password = context.Request.Form["password"];

            var identity = await GetIdentity(username, password);

            if (identity == null)
            {
                context.Response.StatusCode = 400;
                await context.Response.WriteAsync("Invalid username or password.");
                return;
            }

            var now = DateTime.UtcNow;

            var jwt = new JwtSecurityToken(
                claims: identity.Claims,
                notBefore: now,
                expires: now.Add(_options.Expiration),
                signingCredentials: _options.SigningCredentials);

            var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

            var response = new
            {
                access_token = encodedJwt,
                expires_in = (int)_options.Expiration.TotalSeconds,
            };

            context.Response.ContentType = "application/json";
            await context.Response.WriteAsync(JsonConvert.SerializeObject(response, new JsonSerializerSettings { Formatting = Formatting.Indented }));
        }

        private Task<ClaimsIdentity> GetIdentity(string username, string password)
        {
            var user = AccountInMemory.ArrayAccount.FirstOrDefault(x => x.UserName.Equals(username) && x.Password.Equals(password));

            if (user == null) return null;

            IList<Claim> claims = new List<Claim>();

            claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Id, null, ClaimsIdentity.DefaultIssuer, "Provider"));

            claims.Add(new Claim(ClaimTypes.Name, $"{user.FirstName} {user.LastName}", null, ClaimsIdentity.DefaultIssuer, "Provider"));

            claims.Add(new Claim("Username", user.UserName));

            return Task.FromResult(new ClaimsIdentity(claims, "Bearer"));
        }
    }
}

Invoke method: used to check the endpoint if endpoint == "token" will handle the generate token task, or you can handle what is needed because each request it runs through this method.

GenerateToken method: Use to "Verify username and password then generate token".

GetIdentity method: used for creating identiy claim

Open the Startup.cs file, then add the following code.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    string secretKey = "enter_your_sercet_key";

    SymmetricSecurityKey SigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));

    app.UseMiddleware<TokenProviderMiddleware>(Options.Create(new TokenProviderOptions
    {
        SigningCredentials = new SigningCredentials(SigningKey, SecurityAlgorithms.HmacSha256),
    }));

    app.UseJwtBearerAuthentication(new JwtBearerOptions
    {
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = SigningKey,
            ValidateIssuer = false,
            ValidateAudience = false,
        }
    });

    app.UseMvc();
}

First, you need to create a "Serial Key", this key we use to encrypt and decrypt token.

SymmetricSecurityKey is a class that helps us create a SecuretyKey

To play the demo, you should create a web api

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;

namespace ASPNET.Controllers
{
    [Route("api/[controller]")]
    [Authorize]
    public class ValuesController : Controller
    {
        // GET api/values
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}

You should install chrome extension to test your web api.