namespace Diligent.WebAPI.Host.Middlewares { public class JwtMiddleware { private readonly RequestDelegate _next; private readonly AuthorizationSettings _authSettings; public JwtMiddleware(RequestDelegate next, IOptions authSettings) { _next = next; _authSettings = authSettings.Value; } public async Task Invoke(HttpContext context, IUserService userService) { var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last(); if (token != null) await AttachUserToContext(context, userService, token); await _next(context); } private async Task AttachUserToContext(HttpContext context, IUserService userService, string token) { try { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(_authSettings.Secret); tokenHandler.ValidateToken(token, new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = false, ValidateAudience = false, RequireExpirationTime = false, ValidateLifetime = true, // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later) //ClockSkew = TimeSpan.Zero }, out SecurityToken validatedToken); var jwtToken = (JwtSecurityToken)validatedToken; var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value); // attach user to context on successful jwt validation context.Items["User"] = await userService.GetById(userId); await UpdateRefreshToken(context, userService, userId); } catch { // do nothing if jwt validation fails // user is not attached to context so request won't have access to secure routes } } private async Task UpdateRefreshToken(HttpContext context, IUserService userService, int userId) { var refreshToken = await userService.GetRefreshTokenByUserId(userId); if (refreshToken == null) return; refreshToken.ExpiryDate = DateTime.UtcNow.AddMinutes(30); await userService.UpdateRefreshToken(refreshToken); } } }