I would recommend you to write a middleware for this, This will give you better control on what you want to achieve. Like you said it's good to look for an existing solution, but here's one that I'm using in one of my enterprise application.
Intercept Token - Using this middleware on every request
public class JwtMiddleware
{
private readonly RequestDelegate _next;
public JwtMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context, IUserService userService)
{
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
if (token != null) AttachUserToContext(context, userService, token);
await _next(context);
}
private void AttachUserToContext(HttpContext context, IUserService userService, string token)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(AppConfigBuilder.Build().Security.JwtSecret);
tokenHandler.ValidateToken(token, new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero
}, out SecurityToken validatedToken);
var jwtToken = (JwtSecurityToken)validatedToken;
var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value);
context.Items["User"] = userService.GetUserById(userId);
}
catch
{
}
}
}
Register it on StartUp
app.UseMiddleware<JwtMiddleware>();
Then create an Authentication filter
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AuthorizeAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var user = (User)context.HttpContext.Items["User"];
if (user == null)
{
context.Result = new JsonResult(new Response {
IsSuccess = false,
ResponseStatus = ResponseStatus.ERROR,
Message="Request terminated. Unauthorized access to protected resource.",
Info=new List<string>() {
"Verify the auth token sending through this request",
"Verify if your token is invalid or expired",
"Request for a new token by logging in again" }
})
{ StatusCode = StatusCodes.Status401Unauthorized };
}
}
}
That's all need to do. Now for any endpoint to be secured, Just use [Authorize] attribute like this. This will validate your token and emit appropriate standard response.
[HttpGet]
[Authorize]
public IActionResult Get()
{
//Boilerplate code
var response = userService.GetAllUsers();
return (response.IsSuccess) ? Ok(response) : BadRequest(response);
}
Just for info: You can define your own standard Response class on Authorize filter. The one I'm using is from ExpressGlobalExceptionHandler library.
This is the JWT token generation logic I've created
private string GenerateJwtToken(User user)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(appConfig.Security.JwtSecret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[] { new Claim("id", user.Id.ToString()) }),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}