I'm using .net core with IdentityServer 4. I have a Web api, and an MVC app which accesses secure endpoints on the api. It's very similar in setup to the IdentityServer quickstart:
https://github.com/IdentityServer/IdentityServer4.Samples/tree/release/Quickstarts/6_AspNetIdentity
I'm finding that my access_tokens
are expiring, and I'd like to understand how to renegotiate refresh_tokens
.
Take the following code for example (taken from the quickstart here):
public async Task<IActionResult> CallApiUsingUserAccessToken()
{
var accessToken = await HttpContext.Authentication.GetTokenAsync("access_token");
var client = new HttpClient();
client.SetBearerToken(accessToken);
var content = await client.GetStringAsync("http://localhost:5001/identity");
ViewBag.Json = JArray.Parse(content).ToString();
return View("json");
}
If the access_token
has expired, it will fail with 401 response. Is there a built-in mechanism for re-negotiating the access_token
using the refresh_token
?
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.
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 the absolute lifetime.
To get a refresh token, you send a request to your Okta Authorization Server. The only flows that support refresh tokens are the authorization code flow and the resource owner password flow.
IdentityServer is an authentication server that implements OpenID Connect (OIDC) and OAuth 2.0 standards for ASP.NET Core. It's designed to provide a common way to authenticate requests to all of your applications, whether they're web, native, mobile, or API endpoints.
There is not a build in system to refresh the access_token
. However you can use the IdentityModel
package to request a new access_token
with a refresh_token
.
The Client
has a property AllowOfflineAccess
which you should set to true in the IdentityServer. Note that this does not work for the implicit/client credentials flow.
access_token
is about to expire by checking its lifetime and request a new access_token
with the refresh_token
(personal preference)access_token
with the refresh_token
Prior to this code you can check the access_token
lifetime and/or wrap this code in a service before you request a new access_token
var discoveryResponse = await DiscoveryClient.GetAsync("IdentityServer url");
if (discoveryResponse.IsError)
{
throw new Exception(discoveryResponse.Error);
}
var tokenClient = new TokenClient(discoveryResponse.TokenEndpoint, "ClientId", "ClientSecret");
// This will request a new access_token and a new refresh token.
var tokenResponse = await tokenClient.RequestRefreshTokenAsync(await httpContext.Authentication.GetTokenAsync("refresh_token"));
if (tokenResponse.IsError)
{
// Handle error.
}
var oldIdToken = await httpContext.Authentication.GetTokenAsync("id_token");
var tokens = new List<AuthenticationToken>
{
new AuthenticationToken
{
Name = OpenIdConnectParameterNames.IdToken,
Value = oldIdToken
},
new AuthenticationToken
{
Name = OpenIdConnectParameterNames.AccessToken,
Value = tokenResult.AccessToken
},
new AuthenticationToken
{
Name = OpenIdConnectParameterNames.RefreshToken,
Value = tokenResult.RefreshToken
}
};
var expiresAt = DateTime.UtcNow.AddSeconds(tokenResult.ExpiresIn);
tokens.Add(new AuthenticationToken
{
Name = "expires_at",
Value = expiresAt.ToString("o", CultureInfo.InvariantCulture)
});
// Sign in the user with a new refresh_token and new access_token.
var info = await httpContext.Authentication.GetAuthenticateInfoAsync("Cookies");
info.Properties.StoreTokens(tokens);
await httpContext.Authentication.SignInAsync("Cookies", info.Principal, info.Properties);
Taken from and slightly modified: Source
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With