When I followed OpenIDDict refresh flow sample, I constantly got the issue “The refresh token is no longer valid”, which is returned by the following code in my authorization web api controller:

result.Content = new OpenIdConnectResponse
                         Error = OpenIdConnectConstants.Errors.InvalidGrant,
                         ErrorDescription = "The refresh token is no longer valid"

I checked the code and I can find that I followed all the steps in the following Git project:

In the service setup, I have also set the refresh token life time to be 30 days.

options.Configure(config =>
                     // Enable sliding expiration
                     config.UseSlidingExpiration = true;
                     // Set access token expiry time span
                     config.AccessTokenLifetime = TimeSpan.FromMinutes(60);
                     config.RefreshTokenLifetime = TimeSpan.FromDays(30);

‘Root Cause’

By looking into the following code, we can understand that if we cannot find the user principal via Principal property:

var user = await userManager.GetUserAsync(info.Principal);

So the root cause can be: the access token or the refresh token has expired. Since my refresh token life time is 30 days, the only possible cause is that: the access token has expired when it is doing refresh.


Thus, I have implemented a session guard service in my Angular application. This service will regularly check whether access token is going to expire, if is, then call the token refresh authentication api to get the new tokens. The timing is quite important as you need to ensure that access token is valid when refreshing.

The following is the sample code in my Angular application:

checkSessionExpiring(time?: number) {
         /*If session is going to expire then refresh*/
         if (this.authService.isLoggedIn && this.authService.accessTokenExpiryDate != null) {
             if (( + (Constants.TIMER_MILLISECONDS*2)) >= this.authService.accessTokenExpiryDate.valueOf()) {
                 if (!this.isRefreshing) {
                     this.isRefreshing = true;
                     console.log("Refreshing tokens as it is going to expire.");
                     this.authService.refreshLogin().subscribe(user => {
                         this.isRefreshing = false;
                     }, error => {
                         this.isRefreshing = false;
             else {
                 console.log('Session is active.');

The True Root Cause

However, I didn't get this issue in 1.x, which means it still worked in 1.x if access token expired. That is the purpose that to use this refresh token. Root cause: we need to ensure SaveToken property is set to true when setting up OAuth authentication.

// Register the OAuth2 validation handler as required by oidc
             services.AddAuthentication(options =>
                 options.DefaultAuthenticateScheme = OAuthValidationDefaults.AuthenticationScheme;
             }).AddOAuthValidation(options =>
                 options.SaveToken = true;

About author
The opinions and comments expressed herein are my own personal opinions and do not represent my employer's view in any way.
No comments.
Add comment
Title is required.
Name is required.
Please input your personal email with valid format.
Please input comment content.
Captcha Refresh
Input captcha:



Locations of visitors to this page