Auth0 spa 2.x returning missing_refresh_token

I have been receiving errors when calling the getTokenSilently() method. The catch block receives missing_refresh_token and login_required error most of the times.

I have useRefreshToken enabled along with rotation enabled. Leeway 180 seconds.

Here is the code from my axios middleware

const auth0 = getInstance()

try {
      const accessToken = await auth0.getTokenSilently()
      // set axios headers
      config.headers.authorization = `Bearer ${accessToken}`
 } catch (err) {
  console.log(`axios err.error`, err.error)
  if (err.error === 'login_required') {
      window.location.href = auth0.loginWithRedirect()
  } else {
      // throw err
  }
}

Can anyone help identify why am I getting those two errors?

4 Likes

I use the react library with the new v2 version and I am getting missing_refresh_token errors for getAccessTokenSilently method as well.

Same issue after upgrading to v2.

1 Like

@auth0ops ? Any inputs here?

Hi all! If the error is correct in that there is no refresh token available, I have hunch this may be related to the introduction of authorizationParams and a missing offline_access scope in particular. The Auth0Provider in v2 should look like the following (note scope value in authorizationParams):

ReactDOM.render(
  <Auth0Provider
    domain="YOUR_AUTH0_DOMAIN"
    clientId="YOUR_AUTH0_CLIENT_ID"
    authorizationParams={{
      redirect_uri: window.location.origin,
      audience: "YOUR_AUDIENCE_ID",
      scope: "openid profile email offline_access"
    }}
  >
    <App />
  </Auth0Provider>,
  document.getElementById('app')
);

Hope this helps!

1 Like

@tyf @auth0ops by default the library is setting scope as "openid profile email offline_access". Any other inputs?

Howdy, :wave: offline_access is not set by defaullt:

If authorizationParams.scope is not set, the default value is profile email. The only scope that is always applied is openid.

2 Likes

@dan-auth0 @auth0ops We have useRefreshTokens enabled. Which is why the offline_access is being appended.

We have rotation enabled in the auth0 tenant settings. I don’t think we are missing anything from our side. I have checked based on the documentation. But we are still getting missing_refresh_token error.

Note: We are using auth0-spa v2.

2 Likes

Gotcha! Thanks for adding that additional context :pray:

May I ask how you are reproducing this error locally to test it? I’d like to follow the same steps on one of our demos that uses the new SDK such as our Vue.js v2 one:

3 Likes

@dan-auth0 Its happening locally as well as on test and prod tenants.

1 Like

I am also getting this error, even if setting scope and audience. Login still seems to work, but initial load of the page throws this error. Any other ideas @dan-auth0 ?

1 Like

I have the same issue. It started after upgrading to v2.
@dan-auth0 I think the severity of this issue should be raised. This is a serious problem and it affects all our users.

1 Like

I wanted to add my voice to this being a big issue. We also experienced this when moving to v2.

I can see offline_access being passed as part of the scope in the authorize request but when refresh time comes around we get the missing_refresh_token error.

We are getting complaints from high profile customers in prod. Our workaround right now is to have them log out and log back in, but it looks really bad for our company.

1 Like

Hello, all! Thanks for your feedback. Indeed, I am positioning this issue within the SDK team today :+1: I’ll keep you updated as information comes in. Thanks for all the details y’all are providing as that gives us solid context on where to look.

Hello everyone!

I work at the SDK team on Auth0-SPA-JS, and will try to provide some information around whats happening.

Based on the information in the thread, I am not convinced this is a bug. But I am also not saying it can not be a bug, but we will need more information to know that.

But first, let me try and explain why this error shows up in v2, when it never showed up in v1.

TDLR:

Try and set useRefreshTokensFallback to true in v2 (I have also updated our FAQ for this). If that does not restore behavior like you saw it with v1, please read the information below and reach out to us with more information through our GitHub repository.

So what’s going on?

Our SDK has two ways to retrieve a token:

  • Using iframes, which relies on 3rd party cookies (unless using custom domains)
  • Using refresh tokens

When using refresh tokens fails, we fall back to using an iframe based on the value of useRefreshTokensFallback. If it’s true, we try the iframe, if it’s false we throw “missing refresh token” in the event that we do not have a refresh token available. See this check in our SDK.

Based on the v2 migration guide, you can see that we flipped the default value for useRefreshTokensFallback from true to false, this was done because more and more browsers are blocking third party cookies, and not everyone is using custom domains.

What this means if you never explicitly set useRefreshTokensFallback, you will suddenly start seeing missing_refresh_token error with v2, while it was swallowed with v1. This is not a bug, but a consequence of the change in the default value. (we might want to better call this out in the migratoin guide)

In a world where you are using refresh tokens without iframes fallback, when we do not have a refresh token available, there is nothing we can do but throw this error and ask you to call login again with the correct values.

If you would enable the useRefreshTokensFallback, it will get a token using an iframe as long as you have a valid active session with Auth0. If not, it will throw login_required.

Reproducing the issue

I have updated our sample application to reproduce this error in a couple of ways that are expected.

In the sample, you see 3 buttons:

  • One calling getTokenSilently()
  • One calling getTokenSilently({ authorizationParams: { scope: ‘scope-a’}})
  • One calling getTokenSilently({ aughorizationParams: { audience: ‘Test’ }})

Both scope and audience are values that are not set when creating the Auth0Client or when calling loginWithRedirect.When the user is not logged in, calling all 3 of these methods throws missing_refresh_token , which is expected, as we have nothing in our cache.

When the user is logged in, we will get a set of tokens for the default audience and scope (so not for scope-a or audience Test). So when the user is logged in, clicking the first button works. However, the two other still throw the same missing_refresh_token error, as we have nothing in our cache for both scope=scope-a or audience=test. Which is still expected.

Clicking all of these buttons when useRefreshTokensFallback is set to true and there is still an active session with Auth0, will no longer throw the missing_refresh_token error but return tokens instead (or well, if the scope and audience are valid values for your tenant, if not you will get different errors, but no longer missing_refresh_token).

Hopefully this helps to provide some information about the behavior you are seeing with v2. If not, happy to try and assist further.

4 Likes

Thank you @frederik.prijck ! I can confirm that setting useRefreshTokensFallback: true returns the previous behavior.

We are using custom domains, so would you say it’s still best practice NOT to use this setting and adapt appropriately?

1 Like

Hey @stackref-kmcduffee ,

When u use custom domains, settings this to true is definetly a good idea.

Just to be clear, there is nothing wrong in general with setting this to true, if it works better for your situation.

We disabled it by default because there are more and more situations where it doesnt work out of the box (without custom domains). So I would say there is nothing best practise about anything, it depends on your use-case.

But with custom domains, I would always turn it on myself.

3 Likes

But what’s the solution then? Setting useRefreshTokensFallback: true doesn’t sound like a solution but a workaround. How to avoid missing_refresh_token error? You reproduced the issue for 3 different cases in your sample app but it would be nice if you added a working implementation as well. Do we need to include scope and audience when creating Auth0Client?

Hey @serpil.acar,

Enabling the fallback is the solution if you do not want to get MissingRefreshToken errors, and not a workaround.

I also didn’t reproduce any issue, it’s expected behavior for the SDK to have a missing Refresh Token when the fallback is not enabled. As mentioned, this fallback was enabled by default in v1, meaning you never got that error unless u explicitly disabled it. The only reason this error pops up in v2 and not in v1 is because of that, and not because of some bug. So setting it to true again restores behavior as in v1.

But as mentioned, getting a Missing Refresh Token is not a bug or an issue, but our SDK telling you it can not do what you want it to do because it has no refresh token and it can not acquire one.

You either have to enable the fallback, or call loginWithRedirect / loginWithPopup with the correct audience and scope.

Hopefully that helps.

2 Likes

You reproduced the issue for 3 different cases in your sample app but it would be nice if you added a working implementation as well.

Correction I meant you reproduced the “error” not the issue. Thank you for your answer.

That’s what I wanted to know, so I need to use correct audience and scope when calling loginWithRedirect method in order to get a refresh token. Anything else I should do? If it’s written in documentation, a link would be fine as well.

I’m still getting same error even though I use same audience&scope when creating Auth0Client and calling loginWithRedirect method with these. When I use loginWithRedirect with correct audience&scope, does SDK supposed to store refresh token and able to successfully use refresh token whenever I call getTokenSilently method?