public async Task <AuthenticationResponse> RefreshAuthenticationAsync(AuthenticationResponse request) { var principal = GetPrincipalFromAccessToken(request.AccessToken); if (principal == null) { _logger.LogWarning($"[{nameof(RefreshAuthenticationAsync)}] Unable to get principal from access token '{request.AccessToken}'."); throw new AuthenticationServiceUnauthorizedException(); } var user = _userManager.Users.Include(u => u.RefreshTokens).SingleOrDefault(u => u.Id == principal.FindFirstValue(ClaimTypes.NameIdentifier)); if (user == null) { _logger.LogWarning($"[{nameof(RefreshAuthenticationAsync)}] User '{user.Id}' not found."); throw new AuthenticationServiceUnauthorizedException(); } var existingRefreshToken = user.RefreshTokens.SingleOrDefault(t => t.Token == request.RefreshToken); if (!user.IsEnabled || existingRefreshToken == null || (DateTime.UtcNow > existingRefreshToken.ExpiresUtc)) { _logger.LogInformation($"[{nameof(RefreshAuthenticationAsync)}] Refresh token '{request.RefreshToken}' in invalid. Reason: {(!user.IsEnabled ? "User is disabled" : existingRefreshToken == null ? "Token not found" : DateTime.UtcNow > existingRefreshToken.ExpiresUtc ? "Token Expired" : "Unknown")}."); throw new AuthenticationServiceForbiddenException(); } var success = user.RefreshTokens.Remove(existingRefreshToken); _logger.LogInformation($"[{nameof(RefreshAuthenticationAsync)}] Removed refresh token '{existingRefreshToken.Token}' for user '{existingRefreshToken.UserId}'. Success: '{success}'."); var refreshToken = await AuthenticationResponse.GenerateRefreshTokenAsync(); user.RefreshTokens.Add(new RefreshToken { ExpiresUtc = DateTime.UtcNow.Add(Options.BearerRefreshTokenLifespan), Token = refreshToken }); var result = await _userManager.UpdateAsync(user); _logger.LogInformation($"[{nameof(RefreshAuthenticationAsync)}] Added refresh token '{refreshToken}' for user '{existingRefreshToken.UserId}'. Success: '{result.Succeeded}'."); return(new AuthenticationResponse { AccessToken = GetAccessTokenForUser(user), RefreshToken = refreshToken }); }
public async Task <AuthenticationResponse> AuthenticateAsync(AuthenticationRequest request) { var user = await _userManager.FindByIdAsync(request.Id); if (user == null) { _logger.LogWarning($"[{nameof(AuthenticateAsync)}] User '{request.Id}' not found."); throw new AuthenticationServiceUnauthorizedException(); } if (!user.IsEnabled) { _logger.LogWarning($"[{nameof(AuthenticateAsync)}] User '{user.Id}' is disabled."); throw new AuthenticationServiceForbiddenException(); } if (!await _userManager.VerifyUserTokenAsync(user, Options.OtpProvider, Options.OtpPurpose, request.Token)) { _logger.LogWarning($"[{nameof(AuthenticateAsync)}] User '{user.Id}' one-time-password token '{request.Token}' verification failed."); throw new AuthenticationServiceForbiddenException(); } var refreshToken = await AuthenticationResponse.GenerateRefreshTokenAsync(); user.RefreshTokens.Add(new RefreshToken { ExpiresUtc = DateTime.UtcNow.Add(Options.BearerRefreshTokenLifespan), Token = refreshToken }); var result = await _userManager.UpdateAsync(user); _logger.LogInformation($"[{nameof(AuthenticateAsync)}] Added refresh token '{refreshToken}' for user '{user.Id}'. Success: '{result.Succeeded}'."); // This ensures the OTP cannot be used again. result = await _userManager.UpdateSecurityStampAsync(user); _logger.LogInformation($"[{nameof(AuthenticateAsync)}] Updated security stamp for user '{user.Id}'. Success: '{result.Succeeded}'."); return(new AuthenticationResponse { AccessToken = GetAccessTokenForUser(user), RefreshToken = refreshToken }); }