public async Task <IActionResult> RefreshToken(RefreshTokenRequest request) { var(accessToken, refreshToken) = (request.AccessToken, request.RefreshToken); var tokenIsValid = ValidateToken(accessToken); if (!tokenIsValid) { throw new BadRequestException("The token is not valid"); } var claimsPrincipal = GetTokenClaimsPrincipal(request.AccessToken); var expiryDateUnix = long.Parse(claimsPrincipal.Claims.Single(c => c.Type == JwtRegisteredClaimNames.Exp).Value); var expiryDateUtc = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(expiryDateUnix); var tokenHasExpired = DateTime.UtcNow > expiryDateUtc; if (!tokenHasExpired) { throw new BadRequestException("The token has not expired yet"); } var userRefreshToken = _dbContext.RefreshTokens.SingleOrDefault(r => r.RefreshTokenValue == refreshToken); if (userRefreshToken == null) { throw new BadRequestException("The refresh token does not exists"); } var refreshTokenHasExpired = DateTime.UtcNow > userRefreshToken.ExpiryDate; if (refreshTokenHasExpired) { throw new BadRequestException("The refresh token has expired"); } if (userRefreshToken.Invalidated) { throw new BadRequestException("The refresh token has been invalidated"); } var jtiClaimValue = claimsPrincipal.Claims.Single(c => c.Type == JwtRegisteredClaimNames.Jti).Value; var refreshTokenMatchWithTheAccessToken = jtiClaimValue == userRefreshToken.JwtId; if (!refreshTokenMatchWithTheAccessToken) { throw new BadRequestException("The refresh token does not match with the provided access token"); } if (userRefreshToken.Used) { throw new BadRequestException("The refresh token has already been used"); } userRefreshToken.Used = true; _dbContext.RefreshTokens.Update(userRefreshToken); await _dbContext.SaveChangesAsync(); var userId = claimsPrincipal.Claims.Single(c => c.Type == "id").Value; var user = await _userManager.FindByIdAsync(userId); return(GenerateUserAccessTokenAndRefreshToken(user)); }