using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Security.Cryptography; using System.Text; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using UGQApiServer.Settings; using UGQDatabase.Models; namespace JwtRoleAuthentication.Services; public class TokenService { readonly JWTSettings _jwtSettings; public TokenService(IOptions settings) { _jwtSettings = settings.Value; } public string CreateToken(string userGuid, string nickname) { var token = CreateJwtToken(CreateClaims(userGuid, nickname)); var tokenHandler = new JwtSecurityTokenHandler(); return tokenHandler.WriteToken(token); } public string CreateAdminToken(string username, UGQAccountRole role) { var token = CreateJwtToken(CreateAdminClaims(username, role)); var tokenHandler = new JwtSecurityTokenHandler(); return tokenHandler.WriteToken(token); } public string GenerateRefreshToken() { var randomNumber = new byte[32]; using var rng = RandomNumberGenerator.Create(); rng.GetBytes(randomNumber); return Convert.ToBase64String(randomNumber); } public ClaimsPrincipal GetPrincipalFromExpiredToken(string token) { var tokenValidationParameters = new TokenValidationParameters { ValidateAudience = false, //you might want to validate the audience and issuer depending on your use case ValidateIssuer = false, ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Secret)), ValidateLifetime = false //here we are saying that we don't care about the token's expiration date }; var tokenHandler = new JwtSecurityTokenHandler(); SecurityToken securityToken; var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out 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 GenerateAccessTokenFromRefreshToken(string refreshToken, string secret) { // Implement logic to generate a new access token from the refresh token // Verify the refresh token and extract necessary information (e.g., user ID) // Then generate a new access token // For demonstration purposes, return a new token with an extended expiry var tokenHandler = new JwtSecurityTokenHandler(); var key = Encoding.ASCII.GetBytes(secret); var tokenDescriptor = new SecurityTokenDescriptor { Expires = DateTime.UtcNow.AddMinutes(15), // Extend expiration time SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature) }; var token = tokenHandler.CreateToken(tokenDescriptor); return tokenHandler.WriteToken(token); } private JwtSecurityToken CreateJwtToken(List claims) { var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Secret)); DateTime expiration = DateTime.UtcNow.AddMinutes(_jwtSettings.TokenValidityInMinutes); return new( _jwtSettings.ValidIssuer, _jwtSettings.ValidAudience, claims, expires: expiration, signingCredentials: new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256) ); } private List CreateAdminClaims(string username, UGQAccountRole role) { try { var claims = new List { // new Claim(JwtRegisteredClaimNames.Sub, jwtSub), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString()), new Claim(ClaimTypes.Name, username), new Claim(ClaimTypes.Role, role.ToString()) }; return claims; } catch (Exception e) { Console.WriteLine(e); throw; } } private List CreateClaims(string userGuid, string nickname) { try { var claims = new List { // new Claim(JwtRegisteredClaimNames.Sub, jwtSub), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString()), new Claim("Id", userGuid), new Claim(ClaimTypes.Name, nickname), // new Claim(ClaimTypes.Email, user.Email), // new Claim(ClaimTypes.Role, user.Role.ToString()) }; return claims; } catch (Exception e) { Console.WriteLine(e); throw; } } }