Auth0 spa 2.x returning missing_refresh_token

After I set cacheLocation to localstorage when creating Auth0Client, it started working as I want it to be and I no longer get missing_refresh_token error but I wonder why. Was it really the reason for getting this error? If so it may be beneficial if it was mentioned in docs.

1 Like

Were you getting the error on page refresh? If so, using local storage does solve it.

The solution is mentioned in auth0-spa-js/FAQ.md at master · auth0/auth0-spa-js · GitHub, which involves setting useRefreshTokensFallback to true.

If you can not, or do not want to use it, there will be all kinds of reasons the SDK can result in a missing refresh token error and our intent is not to try and avoid these. These are legimate, for example when not using local storage and refreshing the page loses the refresh token, and we are notifying the user about the fact that we have no refresh token. In that case, the solution is:

  • enabling the fallback, which would use iframes when there is no refresh token
  • login again

You can also persist the token, but we try and avoid recommending persisting the token for security reasons when it’s not strictly needed. On top of that, persisting it will not solve all situations, such as when there is no token found or the token is expired.

If you want us to look into it, please share a reproduction of the behavior you are seeing by opening an issue on the SPA-JS repository, and I am happy to dig into what’s happening and explaining.

3 Likes

Following your message about reproducing the missing_refresh_token error using:

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

We’ve set out auth0.loginWithRedirect({ authorizationParams: {...}}) to have the same audience, scope, and redirect_url as our auth0.getTokenSilently({authorizationParams: {...}}) and our new Auth0Client({ authorizationParams: {...}}).
Yet on refresh we still receive Missing Refresh Token (audience: <Same audience for all 3>, scope: 'openid profile email offline_access').
We considered that it might be that we’re passing in a different organization across the three, but when hard-coding the same organisation into all three we still encountered the same issue.

We’re trying to avoid putting access tokens in localstorage if possible, but on the other hand refreshing and throwing users out of the app is a non-option.

We do also have refresh tokens turned on for the application w/ rotation as far as I’m aware.

If you do not use local storage, and you do not have useRefreshTokensFallback enabled, on refresh you will receive a missing refresh token when calling getTokenSilently.

That’s expected, and you need to catch that and call loginWithRedirect.

If you don’t want that, please enable useRefreshTokensFallback, but be aware of the fact that it relies on third party cookies, unless you use custom domains.

Just to be clear, the error has nothing to do with settings in your auth0 dashboard, it’s because you:

  • keep everything in memory
  • tell the sdk to only use refresh tokens and not our iframe fallback
  • refresh the page, so lose every refresh token we ever had
  • try to use a refresh token, but we have none because you just cleared the memory with the refresh, and the SDK is configure to not use any fallback when there is no refresh tokens.

As mentioned, the solution here is to either ensure the cache isnt cleared on refresh (using local storage) or enabling a fallback for when there are no refresh tokens.

Security wise we definetly recommend enabling useRefreshTokensFallback and not the localstorage solution.

2 Likes

So just to be clear, as of now there is no way you are able to use refresh tokens without calling loginWithRedirect or using third-party cookies?. Is the idea that the refresh tokens are just in place so that loginWithRedirect can skip the login steps if the refresh token is still valid?

So just to be clear, as of now there is no way you are able to use refresh tokens without calling loginWithRedirect or using third-party cookies?

Nothing has changed regarding any of this other than the fact that with v2, we flipped the default for useRefreshTokensFallback from true to false. If you want the exact same behavior as with v1, set it to true is all you need.

Refresh tokens solve the fact that, as long as we have a valid refresh token, we do not need to re-authenticate. However, we can not use a refresh token when we have no refresh token (in memor storage + refresh the page results in losing everything, including the refresh token, which is exactly what the error tells you).

If u enable the fallback, we will do a call to Auth0 that does not use refresh tokens under the hood for you to see if we can restore the session silently for you. This is exactly the same as doing loginWithRedirect, apart from the fact that we do it for you hidden in an iframe and only check if there is still a valid session with Auth0 (hence third party cookies).

Again, if this behavior is confusing, setting useRefreshTokensFallback to true is fine and recommended. We flipped the default because, by default, this fallback does not work in browsers that block third party cookies (which will be more over time), and we believe it is weird to have an SDK that, out of the box, does not work on browsers such as Safari (which happens when you set the fallback to true and do not use custom domains).

2 Likes

Thanks a lot @frederik.prijck for helping on that front!

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.