Version 5.x has been out of support since December 13, 2022, and this corresponding section of the documentation is no longer maintained. We strongly recommend upgrading to a supported version.
Access tokens have finite lifetimes. If a client needs long-lived access to a resource, refresh tokens can be used to request a new access token. This can be done with an API call and does not require any user interaction or interruption.
Since this is a privileged operation, the clients needs to be explicitly authorized to be able to use refresh tokens by setting the AllowOfflineAccess property to true. See the client reference section for additional refresh token related settings.
Refresh tokens are supported for the following flows: authorization code, hybrid and resource owner password credential flow.
You can request a refresh token by adding a scope called offline_access to the scope parameter list of the authorize request.
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).
var client = new HttpClient();
var response = await client.RequestRefreshTokenAsync(new RefreshTokenRequest
Address = TokenEndpoint,
ClientId = "client",
ClientSecret = "secret",
RefreshToken = "..."
The IdentityModel.AspNetCore library can be used to automate refresh & access token lifetime management in ASP.NET Core.
Refresh tokens are a high-value target for attackers, because they typically have a much higher lifetime than access tokens.
It is recommended that a refresh token is either bound to the client via a client secret (for confidential/credentialed clients), or rotated for public clients.
The following techniques can be used to reduce the attack surface of refresh tokens.
It’s a good idea to ask for consent when a client requests a refresh token. This way you at least try to make the user aware of what’s happening, and maybe you also give them a chance to opt-out of it.
Duende IdentityServer will always ask for consent (if enabled) if the client asks for the offline_access scope which goes in-line with the recommendations in the OpenID Connect specification.
Refresh tokens usually have a much longer lifetime than access tokens. You can reduce their exposure by adding a sliding lifetime on top of the absolute lifetime. This allows for scenarios where a refresh token can be silently used if the user is regularly using the client, but needs a fresh authorize request if the client has not been used for a certain time. In other words, they auto-expire much quicker without potentially interfering with the typical usage pattern.
You can use the AbsoluteRefreshTokenLifetime and SlidingRefreshTokenLifetime client settings to fine tune this behavior.
Another option is rotating the refresh tokens on every usage. This also reduces the exposure, and has a higher chance to make older refresh tokens (e.g. ex-filtrated from some storage mechanism or a network trace/log file) unusable.
The downside of this approach is that you might have more scenarios where a legitimate refresh token becomes unusable – e.g. due to network problems while refreshing them.
Rotation can be configured via the RefreshTokenUsage client settings and is enabled by default.
On top of one-time only semantics, you could also layer replay detection. This means that if you ever see the same refresh token used more than once, you could revoke all access to the client/user combination. Again – same caveat applies – while increasing the security, this might result in false positives.
See the reference section for more customization of the refresh token service.