using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Text; using IncidentOps.Domain.Enums; using Microsoft.IdentityModel.Tokens; namespace IncidentOps.Infrastructure.Auth; public interface ITokenService { string GenerateAccessToken(Guid userId, Guid orgId, OrgRole orgRole); string GenerateRefreshToken(); string HashToken(string token); } public class TokenService : ITokenService { private readonly JwtSettings _settings; public TokenService(JwtSettings settings) { _settings = settings; } public string GenerateAccessToken(Guid userId, Guid orgId, OrgRole orgRole) { var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_settings.SigningKey)); var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, userId.ToString()), new Claim("org_id", orgId.ToString()), new Claim("org_role", orgRole.ToString().ToLowerInvariant()), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; var token = new JwtSecurityToken( issuer: _settings.Issuer, audience: _settings.Audience, claims: claims, expires: DateTime.UtcNow.AddMinutes(_settings.AccessTokenExpirationMinutes), signingCredentials: credentials ); return new JwtSecurityTokenHandler().WriteToken(token); } public string GenerateRefreshToken() { var randomBytes = new byte[64]; using var rng = RandomNumberGenerator.Create(); rng.GetBytes(randomBytes); return Convert.ToBase64String(randomBytes); } public string HashToken(string token) { var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(token)); return Convert.ToBase64String(bytes); } }