using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using Microsoft.Extensions.Options; using Tiku.Application.Auth; using Tiku.Application.Security; using Tiku.Domain.Tenancy; namespace Tiku.Infrastructure.Auth; public sealed class TokenService(IOptions options, IJwtKeyRing keyRing) : ITokenService { private readonly JwtOptions options = options.Value; public (string Token, DateTimeOffset ExpiresAt) CreateAccessToken( Guid userId, Guid sessionId, string? phone, string? email, AuthRealm realm, Guid? tenantId) { var expiresAt = DateTimeOffset.UtcNow.AddMinutes(options.AccessTokenMinutes); var claims = new List { new(JwtRegisteredClaimNames.Sub, userId.ToString()), new(TikuClaimTypes.SessionId, sessionId.ToString()), new(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")), new(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64), new(TikuClaimTypes.Realm, realm.ToString().ToLowerInvariant()) }; if (tenantId.HasValue) { claims.Add(new Claim(TikuClaimTypes.TenantId, tenantId.Value.ToString())); } if (!string.IsNullOrWhiteSpace(phone)) { claims.Add(new Claim(TikuClaimTypes.Phone, phone)); } if (!string.IsNullOrWhiteSpace(email)) { claims.Add(new Claim(TikuClaimTypes.Email, email)); } var token = new JwtSecurityToken( options.Issuer, options.Audience, claims, expires: expiresAt.UtcDateTime, signingCredentials: keyRing.SigningCredentials); return (new JwtSecurityTokenHandler().WriteToken(token), expiresAt); } }