using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; using Application.Services.Jwt; using Microsoft.Extensions.Configuration; using Microsoft.IdentityModel.Tokens; namespace Infrastructure.Services.Authentication; public class JwtService(IConfiguration configuration) : IJwtService { private readonly string? _audience = configuration["Jwt:Audience"]; private readonly double _expiryMinutes = double.Parse(configuration["Jwt:ExpirationTime"]); private readonly string? _issuer = configuration["Jwt:Issuer"]; private readonly string? _secretKey = configuration["Jwt:SecretKey"]; public string GenerateJwtToken(Guid userId, string roleName, string userName) { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(_secretKey); var tokenDescriptor = new SecurityTokenDescriptor { Subject = new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, userId.ToString()), // User ID as GUID new Claim(ClaimTypes.Role, roleName), // User role as a readable string new Claim(ClaimTypes.Name, userName) // User's name }), Expires = DateTime.UtcNow.AddMinutes(_expiryMinutes), Issuer = _issuer, Audience = _audience, SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); } public bool ValidateJwtToken(string token) { if (string.IsNullOrWhiteSpace(token)) return false; var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(_secretKey); try { tokenHandler.ValidateToken(token, new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = true, ValidateAudience = true, ValidIssuer = _issuer, ValidAudience = _audience, ClockSkew = TimeSpan.Zero }, out var validatedToken); return true; } catch { return false; } } public string RefreshToken(string token) { var principal = ValidateTokenAndGetPrincipal(token); if (principal == null) throw new SecurityTokenException("Invalid token."); var idClaim = principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier); if (idClaim == null || !Guid.TryParse(idClaim.Value, out var id)) throw new SecurityTokenException("Token does not contain a valid ID claim."); var roleClaim = principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Role); var role = roleClaim != null ? roleClaim.Value : "Anonymous"; var nameClaim = principal.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name); var name = nameClaim != null ? nameClaim.Value : "Unknown"; return GenerateJwtToken(id, role, name); } private ClaimsPrincipal ValidateTokenAndGetPrincipal(string token) { var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(_secretKey); try { var principal = tokenHandler.ValidateToken(token, new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(key), ValidateIssuer = true, ValidateAudience = true, ValidIssuer = _issuer, ValidAudience = _audience, ClockSkew = TimeSpan.Zero }, out _); return principal; } catch { // Log or handle validation errors if necessary return null; } } }