using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Text; using Microsoft.IdentityModel.Tokens; namespace Flawless.Server.Services; public class TokenGenerationService { private readonly SymmetricSecurityKey _key; private readonly string _issuer; private readonly double _expiresIn; private readonly double _refreshTokenLifeTime; public TokenGenerationService(IConfiguration c) { var rawKey = Encoding.UTF8.GetBytes(c["Jwt:SecretKey"] ?? throw new Exception("No Jwt:SecretKey")); _key = new SymmetricSecurityKey(rawKey); _issuer = c["Jwt:Issuer"] ?? throw new Exception("No Jwt:Issuer"); _expiresIn = double.Parse(c["Jwt:ExpiresIn"] ?? throw new Exception("No Jwt:ExpiresIn")); _refreshTokenLifeTime = double.Parse(c["Jwt:RefreshTokenLifeTime"] ?? throw new Exception("No Jwt:RefreshTokenLifeTime")); } public double RefreshTokenLifeTime => _refreshTokenLifeTime; public string GenerateToken(IEnumerable claims) { var now = DateTime.UtcNow; var jwt = new JwtSecurityToken( issuer: _issuer, claims: claims, notBefore: now, expires: now.AddMinutes(_expiresIn), signingCredentials: new SigningCredentials(_key, SecurityAlgorithms.HmacSha256) ); return new JwtSecurityTokenHandler().WriteToken(jwt); } public ClaimsPrincipal GetPrincipalFromExpiredToken(string token) { var tokenValidationParameters = new TokenValidationParameters { ValidateAudience = false, ValidateIssuer = true, ValidateLifetime = false, ValidateIssuerSigningKey = true, ValidIssuer = _issuer, IssuerSigningKey = _key, }; var tokenHandler = new JwtSecurityTokenHandler(); var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out var securityToken); var jwtSecurityToken = securityToken as JwtSecurityToken; if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase)) throw new SecurityTokenException("Invalid token"); return principal; } public ClaimsPrincipal GetPrincipal(string token) { var tokenValidationParameters = new TokenValidationParameters { ValidateAudience = false, ValidateIssuer = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = _issuer, IssuerSigningKey = _key, }; var tokenHandler = new JwtSecurityTokenHandler(); var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out var securityToken); var jwtSecurityToken = securityToken as JwtSecurityToken; if (jwtSecurityToken == null || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase)) throw new SecurityTokenException("Invalid token"); return principal; } public string GenerateRefreshToken() { Span randomNumber = stackalloc byte[32]; using var rng = RandomNumberGenerator.Create(); rng.GetBytes(randomNumber); return Convert.ToBase64String(randomNumber); } }