using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Text; using Microsoft.IdentityModel.Tokens; namespace adas_core.Domain.Utils; /// /// Serves as an abstract base class for providing helper functionality related to JSON Web Token (JWT) operations. /// /// /// This class is intended to be inherited by concrete implementations that define specific JWT processing behaviors. /// public abstract class JwtHelper { /// /// Creates a new JWT security token for the specified user, signing it with the provided secret using HMAC-SHA256. /// The token includes standard subject, name, name identifier, and unique token identifier (JTI) claims, and optionally merges any additional claims supplied. /// /// The subject identifier used to populate the token's Sub, Name, and NameIdentifier claims. /// The symmetric secret used to derive the signing key for the token. /// The issuer (iss claim) to associate with the token. /// The audience (aud claim) to associate with the token. /// The token lifetime in minutes, added to the current UTC time to compute the expiration date. /// Optional extra claims to merge into the token alongside the standard claims. If null, only the default claims are included. /// A signed with HMAC-SHA256 and configured with the supplied issuer, audience, expiration, and claims. public static JwtSecurityToken GetJwtToken( string username, string secret, string issuer, string audience, int expiration, Claim[]? additionalClaims = null ) { var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, username), new Claim(ClaimTypes.Name, username), new Claim(ClaimTypes.NameIdentifier, username), // this guarantees the token is unique new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()) }; if (additionalClaims != null) { var claimList = new List(claims); claimList.AddRange(additionalClaims); claims = claimList.ToArray(); } var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret)); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var expireDate = DateTime.UtcNow.AddMinutes(expiration); return new JwtSecurityToken( issuer, audience, expires: expireDate, claims: claims, signingCredentials: creds ); } /// /// Generates a cryptographically secure refresh token by producing 64 random bytes using and returning the value as a Base64-encoded string. /// /// A Base64-encoded string representation of a 64-byte cryptographically random sequence suitable for use as a refresh token. public static string GenerateRefreshToken() { var randomNumber = new byte[64]; using var rng = RandomNumberGenerator.Create(); rng.GetBytes(randomNumber); return Convert.ToBase64String(randomNumber); } /// /// return username from claim /// /// /// public static string? GetUsernameFromPrincipal(ClaimsPrincipal principal) { var nameClaim = principal.Claims.FirstOrDefault(c => c.Type.Equals(ClaimTypes.NameIdentifier)); return nameClaim?.Value; } }