Refresh Tokens¶
Since access tokens have finite lifetimes, refresh tokens allow requesting new access tokens without user interaction.
Refresh tokens are supported for the following flows: authorization code, hybrid and resource owner password credential flow.
The clients needs to be explicitly authorized to request refresh tokens by setting AllowOfflineAccess
to true
.
Additional client settings¶
AbsoluteRefreshTokenLifetime
Maximum lifetime of a refresh token in seconds. Defaults to 2592000 seconds / 30 days. Zero allows refresh tokens that, when used with
RefreshTokenExpiration = Sliding
only expire after the SlidingRefreshTokenLifetime is passed.SlidingRefreshTokenLifetime
Sliding lifetime of a refresh token in seconds. Defaults to 1296000 seconds / 15 days
RefreshTokenUsage
ReUse
the refresh token handle will stay the same when refreshing tokensOneTimeOnly
the refresh token handle will be updated when refreshing tokensRefreshTokenExpiration
Absolute
the refresh token will expire on a fixed point in time (specified by the AbsoluteRefreshTokenLifetime). This is the default.Sliding
when refreshing the token, the lifetime of the refresh token will be renewed (by the amount specified in SlidingRefreshTokenLifetime). The lifetime will not exceed AbsoluteRefreshTokenLifetime.UpdateAccessTokenClaimsOnRefresh
Gets or sets a value indicating whether the access token (and its claims) should be updated on a refresh token request.
Note
Public clients (clients without a client secret) should rotate their refresh tokens. Set the RefreshTokenUsage
to OneTimeOnly
.
Requesting a refresh token¶
You can request a refresh token by adding a scope called offline_access
to the scope parameter.
Requesting an access token using a refresh token¶
To get a new access token, you send the refresh token to the token endpoint. This will result in a new token response containing a new access token and its expiration and potentially also a new refresh token depending on the client configuration (see above).
POST /connect/token
client_id=client&
client_secret=secret&
grant_type=refresh_token&
refresh_token=hdh922
(Form-encoding removed and line breaks added for readability)
Note
You can use the IdentityModel client library to programmatically access the token endpoint from .NET code. For more information check the IdentityModel docs.
Note
The refresh token, must be valid or an invalid_grant error is returned. By default, a refresh_token can only be used once. Using an already used refresh_token will result in an invalid_grant error.
Customizing refresh token behavior¶
All refresh token handling is implemented in the DefaultRefreshTokenService
(which is the default implementation of the IRefreshTokenService
interface):
public interface IRefreshTokenService
{
/// <summary>
/// Validates a refresh token.
/// </summary>
Task<TokenValidationResult> ValidateRefreshTokenAsync(string token, Client client);
/// <summary>
/// Creates the refresh token.
/// </summary>
Task<string> CreateRefreshTokenAsync(ClaimsPrincipal subject, Token accessToken, Client client);
/// <summary>
/// Updates the refresh token.
/// </summary>
Task<string> UpdateRefreshTokenAsync(string handle, RefreshToken refreshToken, Client client);
}
The logic around refresh token handling is pretty involved, and we don’t recommend implementing the interface from scratch, unless you exactly know what you are doing. If you want to customize certain behavior, it is more recommended to derive from the default implementation and call the base checks first.
The most common customization that you probably want to do is how to deal with refresh token replays. This is for situations where the token usage has been set to one-time only, but the same token gets sent more than once. This could either point to a replay attack of the refresh token, or to faulty client code like logic bugs or race conditions.
It is important to note, that a refresh token is never deleted in the database.
Once it has been used, the ConsumedTime
property will be set.
If a token is received that has already been consumed, the default service will call a virtual method called AcceptConsumedTokenAsync
.
The default implementation will reject the request, but here you can implement custom logic like grace periods, or revoking additional refresh or access tokens.