next-auth: CSRF mismatch because of missing cookies

Describe the bug We are currently having trouble with our custom provider because the state verification fails:

[next-auth][error][callback_oauth_error] Error: Invalid state returned from oAuth provider

I looked further into it (with some quick and dirty console.log) and noticed, that the CSRF cookie is renewed after the final redirect and therefore causing a CSRF mismatch.

This seems to be a symptom of not being able to retrieve the expected cookie (next-auth.csrf-token) after returning from the provider. Indeed, both NextAuth cookies (next-auth.csrf-token and next-auth.callback-url) are missing on the GET request that hits /api/auth/callback/custom?code=abc&state=xyz as part of the OAuth callback. But other session cookies used by our application can be found within that request.

Steps to reproduce I am not able to provide a detailed reproduction as this may also depend on the configuration of our internal provider, sorry.

Expected behavior I expect the previously issued CSRF cookie to be found after authenticating on the provider and the state verification to pass.

Additional context As far as I can see, the cookie cannot be found on line 160, the check on 171 fails and then the cookie gets recreated on 176:

https://github.com/nextauthjs/next-auth/blob/78fd783bac990d8f2109487ac6598a38e3173f40/src/server/index.js#L160-L177

Feedback

  • Found the documentation helpful
  • Found documentation but was incomplete
  • Could not find relevant documentation
  • Found the example project helpful
  • Did not find the example project helpful

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 3
  • Comments: 22 (10 by maintainers)

Most upvoted comments

@iaincollins Thanks for looking into this. I am happy to provide the details you asked for:

  • We are only using a single custom provider at the moment, which implements our own OAuth server (based on oidc-provider).
  • Everything is set up with the Client API. The described issue is related to a signIn() call.
  • We saw this in production first (local and staging environment were working fine), but last week it started to happen on my local machine as well. Very wild… 🤷

@balazsorban44 Thank you for the ping. I will try out the canary release and let you know if this changes the issue somehow.

@af608 Thanks for provide some more details. Indeed, it seems to be related to Safari…

@balazsorban44 Thanks for the update and sorry for the late reply! I finally found the time to upgrade NextAuth to v3.18.0 (built-in types, yey!). I can confirm that the state issue is gone as I can see the following in the server console now:

[next-auth][debug][oauth_callback_protection] Comparing received and expected state {
  state: '2b03d568ce05161ea9f5df9b13187ae00e927214c31a5f6133bb79208cef1c98',
  expectedState: '2b03d568ce05161ea9f5df9b13187ae00e927214c31a5f6133bb79208cef1c98'
}

But unfortunately I am still not able to upgrade, because the whole authentication flow is broken for me in newer versions as described in my comment above. Even adding your custom cookies configuration does not help. Should I open a new issue about that?

The more I look into this I have the feeling it’s due to this: https://firebase.google.com/docs/hosting/manage-cache#using_cookies

So with the limitation of cookies being stripped from incoming request and only one possible cookie available called __session, I guess its not possible to use next-auth with firebase hosting… what do you think @balazsorban44 ?

you could try creating a dummy github app for example, or something similar. if you cannot reproduce it with another provider than it might be an issue with yours and we are closer to the solution anyway.

Hooray! I am going to close this issue then!

It sounds like you are having a different issue, and since it was a minor change, breaking is not acceptable, so I kindly ask you to open a new bug report (with a proper reproduction), and I’ll try my best to help you track this down.

The change you mentioned seems irrelevant. Even though the redirect method changed its location, it should still have the exact same behavior as before. But I won’t say it 100% yet. A bug report and reproduction would help terribly much! 🙏

So we moved options.redirect, but the logic did not change, so I don’t think it has changed behavior, but I’ll double check.

Before: https://github.com/nextauthjs/next-auth/blob/85b859231c6948d68749d60d861d65bcbcede6c2/src/server/index.js#L179-L191 After: https://github.com/nextauthjs/next-auth/blob/cdc1ac52b2f20a62a3218ce0f1c7e0aac04c08fb/src/server/lib/extend-req.js#L28-L34

UPDATE: Maybe not calling done() created the issue. Although I never understood the need for done() in the first place, but I have been told it is to mitigate some weird behaviors on some serverless providers.

Hi, I am getting the same error using the latest canary build [3.2.0-canary.35]. The issue seems to be limited to the Safari browser (I am testing with Safari Version 14.0.2 [16610.3.7.1.9]) and it happens only when Safari was restarted. It seems to work fine in Chrome [88.0.4324.96], Brave [v1.19.86 / Chromium: 88.0.4324.96] and Firefox [84.0.2]. As expected, it seems to work on all browser versions with state turned off (“state: false”.)

I tried to use also “protection: pkce”, but this seems to have a similar issue on Safari.

This is the error I am getting with “state: true”

najs-err-state

This is the error with “protection: pkce” najs-err-pkce

Note:

  • Using Provider => type: oauth, version: 2.0 (msal / azure)
  • Using client api call => signIn(“msal”, { callbackUrl: REGISTER_URL })

Hmm, I am not totally sure, the logic how we set the CSRF cookie and how it will compare the state is not planned to change. You can at least follow #1172 to see when I implement it in a PR, and you can test out the canary if it resolves your problem. (semantic-bot will announce in which version #1172 will be included as a comment on the issue)

Thanks for the quick response! You are right, I simply quoted the wrong code… I updated my initial post to align with v3.1.0.

So chances are that the issue is going to be resolved soon anyway? 🎉