JWT Authentication In C# .Net 8 [Bearer token]
JWT in ASP.NET Core
JWT (JSON web token) has become more and more popular in web development. It is an open standard that allows transmitting data between parties as a JSON object in a secure and compact way. The data transmitted using JWT between parties are digitally signed so that it can be easily verified and trusted.
In this article, we will learn how to setup JWT with ASP.NET core web application. We can create an application using Visual Studio or using CLI (Command Line Interface).
Token Provider Class:
namespace Client_DAL.Providers
{
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
public class TokenProvider
{
private readonly string _issuer;
private readonly string _audience;
private readonly SymmetricSecurityKey _signingKey;
public TokenProvider()
{
_signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("[Custom key]"));
_issuer = "MyIssuer[Can be any name]";
_audience = "audience";
}
public JWTToken CreateToken(Guid tokenID, User userDetail)
{
JWTToken result;
if (userDetail != null)
{
var expiry = GetDateTimeNow().AddMinutes(_properties.AuthTokenTimeOut);
var claims = new List
{
new Claim(ClaimTypes.NameIdentifier,tokenID.ToString()),
new Claim(ClaimTypes.Role, userDetail.User_Type),
};
var JWTToken = new JwtSecurityToken(
issuer: _issuer,
audience: _audience,
expires: expiry,
claims: claims,
signingCredentials: new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256)
);
result = new JWTToken
{
Access_Token = new JwtSecurityTokenHandler().WriteToken(JWTToken),
Refresh_Token = GenerateRefreshToken()
};
}
else
{
return null;
}
return result;
}
public JWTToken RefreshToken(JWTToken request, out string errMsg)
{
JWTToken result = null;
errMsg = String.Empty;
var principal = GetPrincipalFromExpiredToken(request.Access_Token, out errMsg);
if (principal == null)
{
errMsg = "Invalid access token or refresh token";
}
var tokenID = principal.FindFirstValue(ClaimTypes.NameIdentifier);
var expiry = DateTime.UtcNow.AddMinutes(_properties.AuthTokenTimeOut);
var JWTToken = new JwtSecurityToken(
issuer: _issuer,
audience: _audience,
expires: expiry,
claims: principal.Claims,
signingCredentials: new SigningCredentials(_signingKey, SecurityAlgorithms.HmacSha256)
);
var newAccessToken = new JwtSecurityTokenHandler().WriteToken(JWTToken);
var newRefreshToken = GenerateRefreshToken();
result = new()
{
Access_Token = newAccessToken,
Refresh_Token = newRefreshToken
};
return result;
}
private ClaimsPrincipal? GetPrincipalFromExpiredToken(string? token, out string errMsg)
{
errMsg = string.Empty;
var tokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKey = _signingKey,
ValidAudience = _audience,
ValidIssuer = _issuer,
ValidateLifetime = true,
ValidateAudience = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = false,
ClockSkew = TimeSpan.FromSeconds(0) //// Identity and resource servers are the same.
};
var tokenHandler = new JwtSecurityTokenHandler();
var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken securityToken);
if (securityToken is not JwtSecurityToken jwtSecurityToken || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
errMsg = "Invalid token";
return principal;
}
private static string GenerateRefreshToken()
{
var randomNumber = new byte[64];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(randomNumber);
return Convert.ToBase64String(randomNumber);
}
public TokenValidationParameters GetValidationParameters()
{
return new TokenValidationParameters
{
IssuerSigningKey = _signingKey,
ValidAudience = _audience,
ValidIssuer = _issuer,
ValidateLifetime = true,
ValidateAudience = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = false,
ClockSkew = TimeSpan.FromSeconds(0) //// Identity and resource servers are the same.
};
}
}
}
Program.cs:
var tokenProvider = new TokenProvider();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = tokenProvider.GetValidationParameters();
});
//// This is for the [Authorize] attributes.
builder.Services.AddAuthorization(auth =>
{
auth.DefaultPolicy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser()
.Build();
});
appsettings.json
"JWTConfig": {
"Secret": "ouenfhsgeifdgskcncbxvsjdgckeh",
"Issuer": "MyAPI",
"Audience": "audience",
"AuthTokenTimeOut": 3600
},
Controller:
////
//// Get profile detail by id
////
//// menu/pages unique code
//// returns profile detail
[HttpGet]
[Authorize(Roles = "Admin, Support")]
[Route("GetUserDetail")]
[ActionName("GetUserDetail")]
public IActionResult Get()
{
return Ok();
}