Open yellowtailfan opened 4 months ago
One suggestion I have seen in your support forms and your GitHub issues is to recover gracefully when receiving an "Invalid state" error by retrying. For example calling getAccessTokenSilently()
with a local storage counter to avoid infinite loops.
I considered trying that, but because I can't reproduce the bug it's hard for me to test the fix. I suppose I could modify my local copy of auth0-react to randomly create the error then check my handling of it that way. But I haven't tried that yet.
It would be great if there was a working and tested example of this kind of retry mechanism. Even better of course would be if the auth0-react library could be made more resilient to transient failures in session storage or overlapping calls to loginWithRedirect()
.
I get the identical error. I literaly followed the SDK React tutorial with React Vite and I cannot handle redirect correctly.
The good news is I was able to fix the problem in our app. We haven't seen an invalid state error for several months.
There were three main changes:
Auth0Provider
including switching on useRefreshTokensFallback
loginWithRedirect()
calls except the login buttongetAccessTokenSilently()
when isAuthenticated
is true
Here's the before and after on the provider options (some of this before case was a mistake I made when upgrading to version 2 of the auth0-react SDK):
Before:
<Auth0Provider
domain={process.env.NEXT_PUBLIC_AUTH0_DOMAIN}
clientId={process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID}
onRedirectCallback={onRedirectCallback}
authorizationParams={ {
redirect_uri: process.env.NEXT_PUBLIC_AUTH0_REDIRECT_URI,
audience: process.env.NEXT_PUBLIC_AUTH0_AUDIENCE,
scope: 'profile email write:data',
cacheLocation: 'localstorage',
useRefreshTokens: true,
useRefreshTokensFallback: true,
} }
>
After:
<Auth0Provider
domain={process.env.NEXT_PUBLIC_AUTH0_DOMAIN}
clientId={process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID}
onRedirectCallback={onRedirectCallback}
cacheLocation='localstorage'
useRefreshTokens={true}
useRefreshTokensFallback={true}
authorizationParams={{
audience: process.env.NEXT_PUBLIC_AUTH0_AUDIENCE,
redirect_uri: process.env.NEXT_PUBLIC_AUTH0_REDIRECT_URI,
scope: 'profile email write:data',
}}
>
I also discovered that overlapping calls to the Auth0 authorize endpoint can cause a state mismatch error which gets displayed to the user as "Invalid state".
There are 3 ways that our code could trigger a call to authorize:
loginWithRedirect()
from index.jsgetAccessTokenSilently()
getAccessTokenSilently()
when calling our APIgetAccessTokenSilently()
has a lock to avoid overlapping requests to the authorize endpoint. But loginWithRedirect()
can also call the authorize endpoint and it doesn't check the getAccessTokenSilently()
lock.
To work around this I have changed our API calls from the client to avoid calling getAccessTokenSilently()
if the user is not authenticated (using isAuthenticated
to check the status). This is because when isAuthenticated
is false
then a loginWithRedirect()
might be already in progress. When loginWithRedirect()
is finished, then isAuthenticated
becomes true
and we can call getAccessTokenSilently()
.
This assumes that the main way isAuthenticated can switch from true
back to false
is if the user logs out.
Checklist
Description
Our production app using auth0-react intermittently produces an "Invalid state" error on our callback page, with error
missing_transaction
.Reproduction
The error is intermittent. I have made many attempts to reproduce it but so far none succeeded.
It happens mostly to myself, several times a day if I am actively using the app on multiple tabs in production on Chrome. It rarely happens for our users. It rarely or never happens on our development server or in local testing. It doesn't seem to affect our other developers using Firefox.
It tends to happen when I have multiple tabs open with our app running, and I switch back to one of those tabs.
Additional context
Our app had 3 authentication triggers:
withAuthenticationRequired
wrapping multiple page componentsloginWithRedirect()
on our index page (not generally open in normal use, as our home screen is on/home
)getAccessTokenSilently()
before each call to our own APIWe are using Nextjs with static export. We are using auth0-react because that was available when we started writing the app several years ago. We are using refresh tokens and the
useCookiesForTransactions
is unset which I believe meansloginWithRedirect()
is using single-tab session storage.My current guesses as to the cause:
loginWithRedirect()
viawithAuthenticationRequired
I considered whether
loginWithRedirect()
on our index page was causing a race condition, but I can't see how that would happen as the index page is never visited after login during normal use.I have made some changes and will keep an eye out to see if the bug has gone:
loginWithRedirect()
from our index page (just rely onwithAuthenticationRequired
that is on our other pages instead)withAuthenticationRequired
optiononBeforeAuthentication
to console and SentryisAuthenticated
before allowing calls togetAccessTokenSilently()
I have also had a detailed discussion with one of your support team on a support ticket.
auth0-react version
2.2.4
React version
17.0.2
Which browsers have you tested in?
Chrome