Create Refresh Token on ASP.NET Web API

[HttpPost("refresh-token")]
public async Task<ActionResult<string>> RefreshToken()
{
    var refreshToken = Request.Cookies["refreshToken"];

    if (!user.RefreshToken.Equals(refreshToken))
    {
        return Unauthorized("Invalid Refresh Token.");
    }
    else if(user.TokenExpires < DateTime.Now)
    {
        return Unauthorized("Token expired.");
    }

    string token = CreateToken(user);
    var newRefreshToken = GenerateRefreshToken();
    SetRefreshToken(newRefreshToken);

    return Ok(token);
}

private RefreshToken GenerateRefreshToken()
{
    var refreshToken = new RefreshToken
    {
        Token = Convert.ToBase64String(RandomNumberGenerator.GetBytes(64)),
        Expires = DateTime.Now.AddDays(7),
        Created = DateTime.Now
    };

    return refreshToken;
}

private void SetRefreshToken(RefreshToken newRefreshToken)
{
    var cookieOptions = new CookieOptions
    {
        HttpOnly = true,
        Expires = newRefreshToken.Expires
    };
    Response.Cookies.Append("refreshToken", newRefreshToken.Token, cookieOptions);

    user.RefreshToken = newRefreshToken.Token;
    user.TokenCreated = newRefreshToken.Created;
    user.TokenExpires = newRefreshToken.Expires;
}

References
https://www.youtube.com/watch?v=HGIdAn2h8BA
https://www.youtube.com/watch?v=LowJMwa7LCU
https://passage.id/post/how-refresh-tokens-work-a-complete-guide-for-beginners?utm_source=pocket_reader
https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/?utm_source=pocket_reader

Decode JWT Token in ASP.NET Web API

var stream = "[encoded jwt]";  
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(stream);
var tokenS = jsonToken as JwtSecurityToken;

Or, without the cast:

var token = "[encoded jwt]";  
var handler = new JwtSecurityTokenHandler();
var jwtSecurityToken = handler.ReadJwtToken(token);

I can get Claims using:

var jti = tokenS.Claims.First(claim => claim.Type == "jti").Value;

References
https://stackoverflow.com/questions/38340078/how-to-decode-jwt-token?utm_source=pocket_reader

Run Code Once at Application Startup in ASP.NET Core

ASP.NET Core interface IHostApplicationLifetime allows developers to subscribe their handlers to ApplicationStarted, ApplicationStopping and ApplicationStopped events

ASP.NET Core provides developers with an IHostedService interface that has StartAsync and StopAsync methods that are executed when the application starts and stops. This interface is typically used to trigger long running background tasks, but StartAsync itself must return quickly so as not to block other hosted services, if any.

public class EInvoiceSenderService: IHostedService {
    private readonly ILogger logger;
    private readonly IHostApplicationLifetime appLifetime;

    public EInvoiceSenderService(
        ILogger<LifetimeEventsHostedService> logger, 
        IHostApplicationLifetime appLifetime) { //<--- INJECTED DEPENDENCY
        this.logger = logger;
        this.appLifetime = appLifetime;
    }

    public Task StartAsync(CancellationToken cancellationToken) {
        appLifetime.ApplicationStarted.Register(OnStarted);
        appLifetime.ApplicationStopping.Register(OnStopping);
        appLifetime.ApplicationStopped.Register(OnStopped);

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken) {
        return Task.CompletedTask;
    }


    private void OnStarted() {
        logger.LogInformation("OnStarted has been called.");

        // Perform post-startup activities here
    }

    private void OnStopping() {
        logger.LogInformation("OnStopping has been called.");

        // Perform on-stopping activities here
    }

    private void OnStopped() {
        logger.LogInformation("OnStopped has been called.");

        // Perform post-stopped activities here
    }    
}

Program.cs

builder.Services.AddHostedService<EInvoiceSenderService>();

References
https://levelup.gitconnected.com/3-ways-to-run-code-once-at-application-startup-in-asp-net-core-bcf45a6b6605
https://stackoverflow.com/questions/59650230/how-to-get-and-inject-the-ihostapplicationlifetime-in-my-service-to-the-containe

Access JWT Token from Controller in ASP.NET Web API

[HttpGet]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public async Task<ActionResult<string>> Get()
{
    var token = await HttpContext.GetTokenAsync("access_token");
    return token;
}
var token = Request.Headers["Authorization"];
var token2 = await HttpContext.GetTokenAsync(JwtBearerDefaults.AuthenticationScheme, "access_token");

References
https://stackoverflow.com/questions/58887151/how-to-access-token-data-from-controller-method
https://stackoverflow.com/questions/52793488/jwt-cannot-be-retrieved-by-httpcontext-gettokenasync-in-net-core-2-1

Get User in ASP.NET Web API

[HttpGet("me"), Authorize]
public async Task<ActionResult<ResponseDto<GetMeResponseDto>>> GetMe()
{
    try
    {
        ResponseDto<GetMeResponseDto> result = new();
        var cts = new CancellationTokenSource();
        var context = await _dbFactory.CreateDbContextAsync(cts.Token);

        var userName = User?.Identity?.Name;

        if (!string.IsNullOrEmpty(userName))
        {
            var user = await context.Users.FirstOrDefaultAsync(x => x.Username == userName,
                cancellationToken: cts.Token);

            if (user != null)
            {
                var role = User!.FindFirstValue(ClaimTypes.Role) ?? string.Empty;

                result.Data = new GetMeResponseDto()
                {
                    Id = user.Id,
                    Username = userName,
                    Role = role,
                };
                result.HasError = false;
            }
        }

        return Ok(result);
    }
    catch (Exception e)
    {
        _logger.LogErrorEx(e, e.Message);
    }

    return BadRequest();
}

Or you can use HttpContext to access it.

References
https://www.youtube.com/watch?v=fhWIkbF18lM
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-7.0
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/use-http-context?view=aspnetcore-7.0
https://www.youtube.com/watch?v=7vqAHD9DlIA

JWT Token Creation, Authentication And Authorization In ASP.NET

Add Nuget Packages

Microsoft.AspNetCore.Authentication.JwtBearer
Microsoft.IdentityModel.Tokens
System.IdentityModel.Tokens.Jwt

Add setting in appsetting.json

"Jwt": {
    "Key": "ACDt1vR3lXToPQ1g3MyN", //Generate random String from https://www.random.org/strings
    "Issuer": "http://localhost:28747/", //Project Property-> Debug-> IIS-->App URL (you can local host url as well)
    "Audience": "http://localhost:28747/"
  },

Register JWT token for Authentication in Program.cs file

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//JWT Authentication
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"]))
    };
});
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();

Create Models (UserLogin, UserModel and UserConstant)

namespace JWTLoginAuthenticationAuthorization.Models
{
    public class UserModel
    {
        public string Username { get; set; }
        public string Password { get; set; }
        public string Role { get; set; }
    }
}
namespace JWTLoginAuthenticationAuthorization.Models
{
    public class UserLogin
    {
        public string Username { get; set; }
        public string Password { get; set; }
    }
}
namespace JWTLoginAuthenticationAuthorization.Models
{
    // We are not taking data from data base so we get data from constant
    public class UserConstants
    {
        public static List<UserModel> Users = new()
            {
                    new UserModel(){ Username="naeem",Password="naeem_admin",Role="Admin"}
            };
    }
}

Create LoginAPI Controller (Authenticate user and generate token)

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

namespace JWTLoginAuthenticationAuthorization.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class LoginController : ControllerBase
    {
        private readonly IConfiguration _config;
        public LoginController(IConfiguration config)
        {
            _config = config;
        }

        [AllowAnonymous]
        [HttpPost]
        public ActionResult Login([FromBody] UserLogin userLogin)
        {
            var user = Authenticate(userLogin);
            if (user != null)
            {
                var token = GenerateToken(user);
                return Ok(token);
            }

            return NotFound("user not found");
        }

        // To generate token
        private string GenerateToken(UserModel user)
        {
            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
            var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
            var claims = new[]
            {
                new Claim(ClaimTypes.NameIdentifier,user.Username),
                new Claim(ClaimTypes.Role,user.Role)
            };
            var token = new JwtSecurityToken(_config["Jwt:Issuer"],
                _config["Jwt:Audience"],
                claims,
                expires: DateTime.Now.AddMinutes(15),
                signingCredentials: credentials);


            return new JwtSecurityTokenHandler().WriteToken(token);

        }

        //To authenticate user
        private UserModel Authenticate(UserLogin userLogin)
        {
            var currentUser = UserConstants.Users.FirstOrDefault(x => x.Username.ToLower() ==
                userLogin.Username.ToLower() && x.Password == userLogin.Password);
            if (currentUser != null)
            {
                return currentUser;
            }
            return null;
        }
    }
}

Create User API Controller to authorize user role

namespace JWTLoginAuthenticationAuthorization.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserController : ControllerBase
    {
        //For admin Only
        [HttpGet]
        [Route("Admins")]
        [Authorize(Roles = "Admin")]
        public IActionResult AdminEndPoint()
        {
            var currentUser = GetCurrentUser();
            return Ok($"Hi you are an {currentUser.Role}");
        }
        private UserModel GetCurrentUser()
        {
            var identity = HttpContext.User.Identity as ClaimsIdentity;
            if (identity != null)
            {
                var userClaims = identity.Claims;
                return new UserModel
                {
                    Username = userClaims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier)?.Value,
                    Role = userClaims.FirstOrDefault(x => x.Type == ClaimTypes.Role)?.Value
                };
            }
            return null;
        }
    }
}

References
https://www.c-sharpcorner.com/article/jwt-token-creation-authentication-and-authorization-in-asp-net-core-6-0-with-po/
https://www.youtube.com/watch?v=UwruwHl3BlU
https://www.youtube.com/watch?v=6sMPvucWNRE

Install Kali Linux in the Windows using WSL

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux

Once rebooted, open the Windows App store and search for the “Kali Linux” application, or alternatively click here to go there directly. Install the app and enjoy Kali!

Install Kali Linux Metapackages

sudo apt update
sudo apt full-upgrade -y
sudo apt install -y kali-linux-default

Install Win-KeX

Win-KeX provides a Kali Desktop Experience for Windows Subsystem for Linux (WSL 2)

sudo apt update
sudo apt install -y kali-win-kex

To start Win-KeX in Window mode with sound support, run

kex --win -s

To start Win-KeX in Enhanced Session Mode with sound support and arm workaround, run

kex --esm --ip -s

To start Win-KeX in Seamless mode with sound support, run

kex --sl -s

Optional Steps

If you have the space, why not install “Kali with the lot”?

sudo apt install -y kali-linux-large

References
https://www.kali.org/blog/kali-linux-in-the-windows-app-store/
https://www.kali.org/docs/general-use/metapackages/
https://www.kali.org/docs/wsl/win-kex/