Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BadRequestError: checks.state argument is missing #145

Closed
nathanchu opened this issue Oct 9, 2020 · 14 comments · Fixed by #159
Closed

BadRequestError: checks.state argument is missing #145

nathanchu opened this issue Oct 9, 2020 · 14 comments · Fixed by #159

Comments

@nathanchu
Copy link

Description

Sometimes while testing this I get:

BadRequestError: checks.state argument is missing
    at <folder>/node_modules/express-openid-connect/middleware/auth.js:105:31
    at processTicksAndRejections (internal/process/task_queues.js:97:5)

This happens randomly after logging in.

Reproduction

It happens especially often at the first login, but sometimes just randomly after logging in. My code:

require('dotenv').config()
const express = require('express')
const app = express()
const { auth } = require('express-openid-connect')
const config = {
  authRequired: false,
  auth0Logout: true,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  secret: process.env.SECRET,
}
app.use(auth(config))
app.get('/', (req, res) => {
  res.send(req.oidc.isAuthenticated() ? 'Logged in. Welcome!' : 'Logged out. <a href="/login">Login?</a>')
})
app.listen(3000)

Environment

  • Version of this library used: 2.0.0
  • Version of the platform or framework used, if applicable: Express version 4.17.1
  • Other relevant versions (language, server software, OS, browser): Node.js version 12.18.4 installed with nvm, macOS 10.15.6, Chrome 85.0.4183.121
  • Other modules/plugins/libraries that might be involved: dotenv version 8.2.0
@adamjmcgrath
Copy link
Contributor

adamjmcgrath commented Oct 12, 2020

Hi @nthnchu - I'm not able to reproduce this.

BadRequestError: checks.state argument is missing would suggest that the transient state cookie is missing when your browser returns to the /callback url.

When you go to /login, the express middleware will leave some cookies with the app state and a nonce (and possibly some others), it'll then use those cookies to verify the token it gets back from the auth server.

A couple of possibilities come to mind about why that cookie is not being read:

  • your browser is replaying the callback request, the first request removes the transient cookie and the second request is throwing the Bad Request error
  • your browser can't read the cookie because somehow it was set with SameSite=Strict, and since the callback page is redirected to from a 3rd party domain the cookie is blocked (is there anything in your chrome console logs when this happens)
  • the cookie was set on a different path, domain or protocol than the callback page - perhaps your switching between http and https or visa versa? What value do you have for BASE_URL and are you visiting the same protocol/domain to login?

Can you do a little more debugging and let me know if you discover anything else or can add any other information about your setup that might be relevant.

@nathanchu
Copy link
Author

nathanchu commented Oct 12, 2020

I'm doing this right now on localhost but will test it on a domain with ssl and see it that works.
My BASE_URL is "http://localhost:3000"

@fire015
Copy link

fire015 commented Oct 20, 2020

I am also getting the same issue randomly on localhost:3000

@adamjmcgrath
Copy link
Contributor

Hey @fire015 - thanks for sharing. Do you have an app or any steps where you can reliably reproduce it?

@fire015
Copy link

fire015 commented Nov 3, 2020

Afraid not :(

@adamjmcgrath
Copy link
Contributor

adamjmcgrath commented Nov 5, 2020

Hi @nthnchu @fire015 - I think we've got to the bottom of this:

If you're on http (localhost) and using response_mode: form_post (the default), logins that take longer than 2 mins will fail with checks.state argument is missing because of Chrome's 2 min exception for SameSite=Lax+POST, we recommend you run your localhost behind an https proxy in development to work around this.

This wouldn't happen in prod because you should be running your app over https (just make sure that, if you're running your app behind an offloading https proxy, you set trust proxy appropriately.)

@nathanchu
Copy link
Author

Would a self signed SSL cert work? Or should I be using something like ngrok for a real one?

@panva
Copy link
Contributor

panva commented Nov 6, 2020

Any TLS connection or trusted proxy infront will do.

@sheunglaili
Copy link

I've setup a https nginx proxy with custom signed cert in front of my express server, but the issue still occur

@nathanchu
Copy link
Author

@sheunglaili Did you add app.set('trust proxy', true)

@sheunglaili
Copy link

sheunglaili commented Dec 10, 2020

@sheunglaili Did you add app.set('trust proxy', true)

Yes. I added .

const app = express();
app.set('trust proxy', true)

app.use(auth({
  authRequired: false,
  auth0Logout: true,
  secret: process.env.AUTH_SECRET,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
}))

I even try with Caddy, still no luck. Will custom local host name with /etc/hosts affect this ?

@sheunglaili
Copy link

I figured it out. As I using custom domain name, I should specify the domain name on the cookies

app.use(auth({
  authRequired: false,
  auth0Logout: true,
  session: {
    //@ts-ignore
    cookie: {
      domain: '.example.com'
    }
  },
  secret: process.env.AUTH_SECRET,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
}))

@wisammechano
Copy link

I figured it out. As I using custom domain name, I should specify the domain name on the cookies

app.use(auth({
  authRequired: false,
  auth0Logout: true,
  session: {
    //@ts-ignore
    cookie: {
      domain: '.example.com'
    }
  },
  secret: process.env.AUTH_SECRET,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
}))

This helped me when I was using gitpod to test my dev application. Gitpod issues a custom subdomain for each port exposed and uses https as well

@akhil7626
Copy link

I think this is happening if you are already logged in and you try to login again using the login screen.

adrienjoly pushed a commit to openwhyd/openwhyd that referenced this issue Dec 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants