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;
}
}