I just wanted to post this here because it took me about 12 hours to solve this problem and I wanted to help others who may have run into it!
The Problem
I had an issue in using the @auth0/auth0-react
package in a SPA where I was running on http://localhost:8080
, it would throw a state mismatch error after correctly authorizing in the new Auth0 login redirect page. I would notice in the URL params that the state Auth0 generated for the login was different than the one it was returned/sent to the callback url. It felt like a race condition at first because it happened about 80% of the time we tried to log in.
A manual refresh reset the state and worked every time.
Honestly, searching online returned very limited results, but I tried:
- Using refresh tokens
- Using the
useCookiesForTransactions
param forAuth0Provider
- Adding a specific
/callback
url, react-routerRoute
, and component - Setting my own cookies (even though it was a SPA) as with this WordPress Invalid State Error article suggested
- Downgrading react-router to v5.3 from v6
- Downgrading React from v18.x to v17.x
- Using
https
instead ofhttp
(yes, even forlocalhost
) - etc
The error I would get back had a stack trace that included lines in webpack’s source code.
Specs
Relevant package declarations in package.json
:
@auth0/auth0-react": "^1.12.0"
"react": "^18.1.0"
"react-dom": "^18.1.0"
"react-router-dom": "^6.4.3"
"webpack": "^5.72.0"
"webpack-cli": "^4.9.2"
"webpack-dev-server": "^4.9.0"
Other information:
- Mac OSX 12.4
- Google Chrome Version 107.0.5304.110
The Solution
Are you ready? It’s super dumb.
…
…
…
Disabling HMR in Webpack.
We were running with hot: true
in our webpack config and it caused our app to re-render unnecessarily (even without extra saves while logging in). I’m still not sure exactly why this caused Auth0 to trip up, but it might make sense that since it re-rendered a few extra times when redirecting to the callback, that Auth0 might have thought it was a CSRF attack.
So any of the solutions would work for this problem:
- Add
hot: false
to yourwebpack.config.js
module.exports = {
...
devServer: {
hot: false
...
}
}
- Add
watch: false
to your webpack config
module.exports = {
...
watch: false
}
- Use
webpack-dev-server
without the--hot
flag
Ok. I hope that helps someone save some time. It stumped me and my friend, who graciously decided to help me debug, for a good long while.
Would love to know exactly why this happens, but I’m also just happy with knowing the fix!