-
-
Notifications
You must be signed in to change notification settings - Fork 335
Closed
Labels
Description
Lines 34 to 63 in 9d19a93
| // Note: this handler can be called concurrently for the same user if multiple HTTP | |
| // requests are processed in parallel: while this results in multiple refresh token | |
| // requests being sent concurrently, this is something OpenIddict allows during a short | |
| // period of time (called refresh token reuse leeway and set to 30 seconds by default). | |
| var result = await _service.AuthenticateWithRefreshTokenAsync(new RefreshTokenAuthenticationRequest | |
| { | |
| CancellationToken = cancellationToken, | |
| DisableUserInfo = true, | |
| RefreshToken = GetRefreshToken(request.Options) | |
| }); | |
| request.Headers.Authorization = new AuthenticationHeaderValue(Schemes.Bearer, result.AccessToken); | |
| return new TokenRefreshingHttpResponseMessage(result, await base.SendAsync(request, cancellationToken)); | |
| } | |
| // Otherwise, don't bother using the existing access token and refresh tokens immediately. | |
| else | |
| { | |
| var result = await _service.AuthenticateWithRefreshTokenAsync(new RefreshTokenAuthenticationRequest | |
| { | |
| CancellationToken = cancellationToken, | |
| DisableUserInfo = true, | |
| RefreshToken = GetRefreshToken(request.Options) | |
| }); | |
| request.Headers.Authorization = new AuthenticationHeaderValue(Schemes.Bearer, result.AccessToken); | |
| return new TokenRefreshingHttpResponseMessage(result, await base.SendAsync(request, cancellationToken)); | |
| } |
When _service.AuthenticateWithRefreshTokenAsync fails, it is returning an error.
I should expect to return a 401
solution is putting the AuthenticateWithRefreshTokenAsync within a try catch
// If an access token expiration date was returned by the authorization server and stored
// in the authentication cookie, use it to determine whether the token is about to expire.
// If it's not, try to use it: if the resource server returns a 401 error response, try
// to refresh the tokens before replaying the request with the new access token attached.
var date = GetBackchannelAccessTokenExpirationDate(request.Options);
if (date is null || TimeProvider.System.GetUtcNow() <= date?.AddMinutes(-5))
{
request.Headers.Authorization = new AuthenticationHeaderValue(Schemes.Bearer, GetBackchannelAccessToken(request.Options));
var response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode is not HttpStatusCode.Unauthorized)
{
return response;
}
// Note: this handler can be called concurrently for the same user if multiple HTTP
// requests are processed in parallel: while this results in multiple refresh token
// requests being sent concurrently, this is something OpenIddict allows during a short
// period of time (called refresh token reuse leeway and set to 30 seconds by default).
return await TryWithRefreshTokenAsync(request, cancellationToken);
}
// Otherwise, don't bother using the existing access token and refresh tokens immediately.
else
{
return await TryWithRefreshTokenAsync(request, cancellationToken);
}
async Task<HttpResponseMessage> TryWithRefreshTokenAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
var result = await _service.AuthenticateWithRefreshTokenAsync(new RefreshTokenAuthenticationRequest
{
CancellationToken = cancellationToken,
DisableUserInfo = true,
RefreshToken = GetRefreshToken(request.Options)
});
request.Headers.Authorization = new AuthenticationHeaderValue(Schemes.Bearer, result.AccessToken);
return new TokenRefreshingHttpResponseMessage(result, await base.SendAsync(request, cancellationToken));
}
catch (Exception ex)
{
// Refresh token failed, returning 401
var response = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
RequestMessage = request
};
return response;
}
}
Reactions are currently unavailable