using Knot.Contracts.Auth.Application.Abstractions; using Knot.Contracts.Auth.Application.Auth.DTOs; using Knot.Contracts.Auth.Domain; using Knot.Shared.Kernel; using MediatR; namespace Knot.Modules.Auth.Application.Users.RefreshToken; internal sealed class RefreshTokenCommandHandler : ICommandHandler { private readonly IUserRepository _userRepository; private readonly IJwtTokenProvider _tokenProvider; public RefreshTokenCommandHandler( IUserRepository userRepository, IJwtTokenProvider tokenProvider) { _userRepository = userRepository; _tokenProvider = tokenProvider; } public async Task> Handle(RefreshTokenCommand request, CancellationToken cancellationToken) { if (string.IsNullOrWhiteSpace(request.RefreshToken)) { return Result.Failure( new Error("Auth.InvalidRefreshToken", "Refresh token is required")); } var user = await _userRepository.GetByRefreshTokenAsync(request.RefreshToken, cancellationToken); if (user == null) { return Result.Failure( new Error("Auth.InvalidRefreshToken", "Invalid or expired refresh token")); } // Check if refresh token has expired if (user.RefreshTokenExpiry.HasValue && user.RefreshTokenExpiry.Value < DateTime.UtcNow) { // Clear expired refresh token user.SetRefreshToken(null, null); await _userRepository.UpdateAsync(user, cancellationToken); return Result.Failure( new Error("Auth.RefreshTokenExpired", "Refresh token has expired. Please login again.")); } var newAccessToken = _tokenProvider.Generate(user.Id, user.Username, user.DisplayName, user.Avatar); var newRefreshToken = _tokenProvider.GenerateRefreshToken(); var newRefreshExpiry = _tokenProvider.GetRefreshTokenExpiry(); user.SetRefreshToken(newRefreshToken, newRefreshExpiry); await _userRepository.UpdateAsync(user, cancellationToken); return Result.Success(new AuthResponseDto { AccessToken = newAccessToken, RefreshToken = newRefreshToken, UserId = user.Id, Username = user.Username, DisplayName = user.DisplayName, Avatar = user.Avatar }); } }