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

CallbackHandlerError: Callback handler failed. CAUSE: Missing state cookie #1411

Closed
6 tasks done
jmsherry opened this issue Sep 1, 2023 · 35 comments
Closed
6 tasks done
Labels
question Further information is requested

Comments

@jmsherry
Copy link

jmsherry commented Sep 1, 2023

Checklist

Description

Getting the now infamous:

CallbackHandlerError: Callback handler failed. CAUSE: Missing state cookie from login request (check login URL, callback URL and cookie config).
    at /Users/jamessherry/sites/auth0-base-case/node_modules/@auth0/nextjs-auth0/dist/handlers/callback.js:74:15
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async /Users/jamessherry/sites/auth0-base-case/node_modules/@auth0/nextjs-auth0/dist/handlers/auth.js:79:13 {
  code: 'ERR_CALLBACK_HANDLER_FAILURE',
  cause: MissingStateCookieError: Missing state cookie from login request (check login URL, callback URL and cookie config).
      at /Users/jamessherry/sites/auth0-base-case/node_modules/@auth0/nextjs-auth0/dist/auth0-session/handlers/callback.js:17:19
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
      at async /Users/jamessherry/sites/auth0-base-case/node_modules/@auth0/nextjs-auth0/dist/handlers/callback.js:71:16
      at async /Users/jamessherry/sites/auth0-base-case/node_modules/@auth0/nextjs-auth0/dist/handlers/auth.js:79:13 {
    status: 400,
    statusCode: 400
  },
  status: 400
}

Reproduction

Demo Repo

bare bones version of the sample app: (https://github.com/jmsherry/auth0-base-case)
CodeSandbox (using that repo): https://codesandbox.io/p/github/jmsherry/auth0-base-case/draft/festive-dan?file=/.env.local:7,21&workspaceId=a7a0b083-be25-46b2-a16c-f0ff761d57bf

Steps

  1. Follow the documentation and create a project
  2. Wire it up to an auth0 instance of a regular web app (as per ^^ documentation)
  3. Go to the login route
  4. Get 400 (and confirm that on the Auth0 side login was successful)

Additional context

My ticket on the help forums: https://community.auth0.com/t/missing-state-cookie-from-login-request-yes-another-one/115032 (details of versions and debug attempts can be found there)

There are plenty of other tickets too:

(There are lots of 'it just fixed itself' which suggests to me a reload triggering cookies to be cleared or reset for a domain.)

nextjs-auth0 version

3.1.0

Next.js version

13.4.19

Node.js version

18.1.0

@wasifhassan101
Copy link

Hey, I reproduced the nextjs-auth0 sample app, but it seems to work fine on my end. I see that problem on your end started occurring after adding middleware. Can you provide the code you think caused this issue?

Probably unrelated, but getSession in middleware in one of my projects was deleting cookies, so looking at getSession and utilizing the response from it might help.

@jmsherry
Copy link
Author

jmsherry commented Sep 1, 2023

Hey, I reproduced the nextjs-auth0 sample app

Sorry, do you mean the minimal repo I created from that app or the actual sample app?

but it seems to work fine on my end.

This is one of the problems. It's intermittent [as in it's fine initially, then] as soon as you do <something, we don't know what: may involve middleware> it just borks it until some sort of reset happens. The code I have here will run fine remotely, for example, but will fail on localhost.


As for middleware, this was the first thing I used (from the docs) and then reverted back to:

import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export function middleware(request: NextRequest) {
  // Clone the request headers and set a new header `x-hello-from-middleware1`
  const requestHeaders = new Headers(request.headers);
  requestHeaders.set("x-hello-from-middleware1", "hello");

  // You can also set request headers in NextResponse.rewrite
  const response = NextResponse.next({
    request: {
      // New request headers
      headers: requestHeaders,
    },
  });

  // Set a new response header `x-hello-from-middleware2`
  response.headers.set("x-hello-from-middleware2", "hello");
  return response;
}

export const config = {
  matcher: '/courses/:course/:tutor*',
}

This was the custom middleware I put in when the problems may have started:

 import { NextResponse } from "next/server";
 import { withMiddlewareAuthRequired, getSession } from '@auth0/nextjs-auth0/edge';
 import type { NextRequest } from "next/server";


// // import Router from "next/router";

 export default withMiddlewareAuthRequired(async function middleware(
   req: NextRequest
 ) {
   try {
     const res = NextResponse.next();
     const user = await getSession(req, res);


     console.log("user", user);
     // const isAdmin = checkRole(user, identifier, adminRole);
     // console.log("isAdmin", isAdmin);
    
     // if (!isAdmin) {
     //   return NextResponse.redirect(new URL("/", req.url));
     // }
     return res;
   } catch (err) {
     // console.log("in error", err);
     // If not logged in
     NextResponse.redirect(new URL("/api/auth/login", req.url));
   }
 });

export const config = {
   matcher: [
     /*
      * Match all request paths except for the ones starting with:
      * - api (API routes)
      * - _next/static (static files)
      * - _next/image (image optimization files)
      * - favicon.ico (favicon file)
      */
     "/((?!api/auth|_next/static|_next/image|favicon.ico).*)",
   ],
 };

@alexng353
Copy link

I'm having the same problem but it comes with this error:

CallbackHandlerError: Callback handler failed. CAUSE: access_denied (Cannot find module &#39;request@2.56.0&#39;
Require stack:
- /data/io/node18/e6d0cbdd-00c1-44a5-bfa1-5ceb7770678f/webtask.js)
    at eval (webpack-internal:///(rsc)/../../node_modules/.pnpm/@auth0+nextjs-auth0@3.1.0_next@13.4.19/node_modules/@auth0/nextjs-auth0/dist/handlers/callback.js:60:19)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async eval (webpack-internal:///(rsc)/../../node_modules/.pnpm/@auth0+nextjs-auth0@3.1.0_next@13.4.19/node_modules/@auth0/nextjs-auth0/dist/handlers/auth.js:59:24)
    at async eval (webpack-internal:///(rsc)/../../node_modules/.pnpm/next@13.4.19_@babel+core@7.22.11_react-dom@18.2.0_react@18.2.0_sass@1.66.1/node_modules/next/dist/server/future/route-modules/app-route/module.js:254:37) {
  code: 'ERR_CALLBACK_HANDLER_FAILURE',
  cause: IdentityProviderError: access_denied (Cannot find module &#39;request@2.56.0&#39;
  Require stack:
  - /data/io/node18/e6d0cbdd-00c1-44a5-bfa1-5ceb7770678f/webtask.js)
      at NodeClient.callback (webpack-internal:///(rsc)/../../node_modules/.pnpm/@auth0+nextjs-auth0@3.1.0_next@13.4.19/node_modules/@auth0/nextjs-auth0/dist/auth0-session/client/node-client.js:133:23)
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
      at async eval (webpack-internal:///(rsc)/../../node_modules/.pnpm/@auth0+nextjs-auth0@3.1.0_next@13.4.19/node_modules/@auth0/nextjs-auth0/dist/auth0-session/handlers/callback.js:40:29)
      at async eval (webpack-internal:///(rsc)/../../node_modules/.pnpm/@auth0+nextjs-auth0@3.1.0_next@13.4.19/node_modules/@auth0/nextjs-auth0/dist/handlers/callback.js:57:13)
      at async eval (webpack-internal:///(rsc)/../../node_modules/.pnpm/@auth0+nextjs-auth0@3.1.0_next@13.4.19/node_modules/@auth0/nextjs-auth0/dist/handlers/auth.js:59:24)
      at async eval (webpack-internal:///(rsc)/../../node_modules/.pnpm/next@13.4.19_@babel+core@7.22.11_react-dom@18.2.0_react@18.2.0_sass@1.66.1/node_modules/next/dist/server/future/route-modules/app-route/module.js:254:37) {
    error: 'access_denied',
    errorDescription: 'Cannot find module &#39;request@2.56.0&#39;\n' +
      'Require stack:\n' +
      '- /data/io/node18/e6d0cbdd-00c1-44a5-bfa1-5ceb7770678f/webtask.js',
    status: 400,
    statusCode: 400,
    openIdState: { returnTo: 'http://localhost:3000/' }
  },
  status: 400
}

@jmsherry
Copy link
Author

jmsherry commented Sep 4, 2023

@alexng353 That sounds like it's missing the 'request' module internally. Have you tried a rimraf and reinstall of node_modules?

@alexng353
Copy link

@jmsherry yeah here's some more information #1414

@jmsherry
Copy link
Author

jmsherry commented Sep 5, 2023

Managed to get a solution by manually copying the cookies across like res.cookies = {...req.cookies, ...res.cookies};

I suspect that a double-reload was part of it. I also suspect that any manual clearing of cookies, etc. or addition of any programming in the pipeline may cause the cookies not to be set...

import util from "node:util";
console.log('inspect',util.inspect);
import { handleAuth, handleLogin } from "@auth0/nextjs-auth0";

const auth = handleAuth({
  async login(req, res) {
    console.log('url', req.url);
    console.log('query', req.query);
    try {
      console.log('auth cookies', util.inspect(req.cookies, {
        showHidden: true,
        colors: true,
        depth: null,
      }));
      res.cookies = {...req.cookies, ...res.cookies}; // <--- HERE!

      // console.log('auth cookies', req.cookies?.getAll?.());
       // Pass in custom params to your handler
      await handleLogin(req, res);
      // Add your own custom logging.
      console.log('Redirecting to login');

    } catch (error) {
      // Add you own custom error logging.
      console.log(error);
      res.status(error.status || 500).end();
    }
  },
  onError(request) {
    console.log('error request', request.nextUrl)
    console.log('auth error cookies', util.inspect(request, {
      showHidden: true,
      colors: true,
      depth: null,
    }));
  },
});



export default auth;

I'm not holding my breath for stability though! We'll see if this lasts!

@alexng353
Copy link

@jmsherry were you able to reproduce the error?

@jmsherry
Copy link
Author

jmsherry commented Sep 5, 2023

@alexng353 I've not! But I'll tell you, I've had so many breaks in the build process and dev server today it's ridiculous! Feels like building on sand! You never know what error it's going to throw next.

If I do I'll reply to your ticket and let you know what I find!

@jmsherry
Copy link
Author

jmsherry commented Sep 5, 2023

@alexng353 Actually, try my suggestion (that I've just posted) because I was getting build errors like 'cannot find inspect in webpack_import.default' when trying to use util inspect. Once I did the above the build issue seemed to fix itself, so it may help...

@alexng353
Copy link

@jmsherry thanks for the info, I'll be sure to check it out

@adamjmcgrath
Copy link
Contributor

Hi @jmsherry - thanks for raising this

And thanks for sharing that repo, I can't reproduce any issues with it, I'm able to login consistently without problem.

I've also tried adding the middleware you shared and your custom login handler.

It looks like you've resolved the issues, so closing - but if you have a reproducible example to share or want me to take a look at a HAR file, feel free to ping me and I'll reopen

@chad-jump
Copy link

chad-jump commented Sep 7, 2023

Hi @adamjmcgrath ,
Please see HAR file attached. That's for the journey of loading the base-case project and then navigating to the login endpoint...

Helpfully gh seems not to allow HAR as an attachment, so: https://test-bucket555755.s3.eu-west-2.amazonaws.com/localhost_Archive+%5B23-09-07+13-53-58%5D.har

EDIT: Sorry Adam, this is posted from another gh account but it's me (@jmsherry )

@jmsherry
Copy link
Author

jmsherry commented Sep 7, 2023

@adamjmcgrath FYI, even with my fix, Issue is back when I changed over keys from one Auth0 account to another.

@alexng353
Copy link

The issue definitely has to do with the account linking plug-in. Disabling it fixed the problem for me, so we are not doing account linking until this is resolved. Auth0 side for sure since I tested this in the example repo.

@jmsherry
Copy link
Author

jmsherry commented Sep 8, 2023

@alexng353 Thanks for the info. I don't have that plugin installed but there's clearly something really wrong here and it is on the Auth0 side. Given the Auth0 logs indicate a successful login and the journey to/from Auth0 servers is fine, I'm guessing this is something to do with the SDK's callback handler and what happens when the state parameter goes out so sync (because of a change in pipeline (e.g. the addition of middleware), which stops the cookies getting passed on, or; because the cookies (and storage?) were manually cleared via the developer tools; or because env vars get changed).

If anyone from Auth0 wants to investigate further I'd be fully prepared to give them details of my Auth0 app and access to my machine to see what's going on?!

@jmsherry
Copy link
Author

jmsherry commented Sep 13, 2023

Hi @adamjmcgrath, wondering if there's any update on this and if you want to re-open the ticket and consider any of the offers I've made above as this is REALLY affecting me and my company!

I have a video of the issue and I can provide any details. This issue persists across browser and accounts.

Thanks Adam.

@adamjmcgrath
Copy link
Contributor

Hi @jmsherry - thanks for sharing the HAR file and the video

In your HAR file, the /api/auth/login response does not set any cookies - I would expect to see a set-cookie header setting the auth_verification cookie in the response headers for the /api/auth/login request, but I don't see any:

Your HAR:
image

When I run your sample app (jmsherry/auth0-base-case - master branch) - the response from the login request does set an auth_verification cookie and I'm able to login successfully:
image

Can you confirm that attempting to login to your sample app fails with "Callback handler failed. CAUSE: Missing state cookie from login request" - because it seems to work correctly for me.

@adamjmcgrath adamjmcgrath reopened this Sep 13, 2023
@PorridgeBear
Copy link

Getting this exact issue with fairly out-of-the-box implementation as described by the Auth0 Quick Start. Using Next.js latest 3.4.19 and nextjs-auth0 3.1.0.

It is related to the duration away from the application after having successfully signed in before.

The steps are:

  • Sign in via auth0 universal login, callback to site works, an appSession cookie is set
  • Life is good
  • Go to sleep
  • Come back the next day, open the site, middleware (due to lower token expiry config in dev) kicks user back out to homepage
  • Sign in, universal login with email/password is shown correctly, but this time the callback experiences this Missing state cookie from login request (check login URL, callback URL and cookie config). - the page URL is e.g. http://myapp.localhost:3000/api/auth/callback?code=xxx&state=yyy with a Chrome 400 status code

To get past this, I go back to my homepage, init the auth0 sign in a second time, and now I don't even see the universal login, no need for email/password - I am just logged straight into my application's dashboard.

In terms of my implementation:

  • Sign in button from homepage points to /api/auth/login?returnTo=/dashboard
  • Middlware as follows
import { withMiddlewareAuthRequired } from "@auth0/nextjs-auth0/edge";

export default withMiddlewareAuthRequired();

export const config = {
  matcher: "/dashboard/:path*",
};
  • And /api/auth/[auth0]/route.js is:
import { handleAuth } from "@auth0/nextjs-auth0";

export const GET = handleAuth();

Nothing special as far as I can see here, just a protected route and out-of-the-box install of this library.

HTH!

@jmsherry
Copy link
Author

jmsherry commented Sep 13, 2023

@adamjmcgrath

Can you confirm that attempting to login to your sample app fails with "Callback handler failed. CAUSE: Missing state cookie from login request" - because it seems to work correctly for me.

Well, now it's not failing with that error: https://test-bucket555755.s3.eu-west-2.amazonaws.com/13-9-basic-app.har
The cookie is being set but it still fails.

Server logs don't reveal anything of note. Logins in dashboard are successful.

@jmsherry
Copy link
Author

@PorridgeBear TY. :)

I'd heard of that approach and tried it myself but to no avail...

@jmsherry
Copy link
Author

jmsherry commented Sep 13, 2023

@adamjmcgrath That error in the video when I did pnpm dev was: vercel/next.js#53837. Not sure if that's effecting it...

@adamjmcgrath
Copy link
Contributor

Thanks for sharing another HAR file @jmsherry

Well, now it's not failing with that error: test-bucket555755.s3.eu-west-2.amazonaws.com/13-9-basic-app.har

Unfortunately, I can't see any cookies being read or set on localhost in the har file you've shared, so there's not much I can tell you from it I'm afraid.

Also, I can't reproduce the issue in the sample app you've shared.

So without a reproducible example or any useful information in your har file, there's not much I can suggest at the moment.

@adamjmcgrath adamjmcgrath added the question Further information is requested label Sep 14, 2023
@PorridgeBear
Copy link

@adamjmcgrath here's a HAR https://drive.google.com/file/d/1NotIninjvr32LDBPUuZ7j91ED83Fx6Tb/view?usp=sharing for what I was describing above, which is now entirely reproduceable by waiting overnight for the token to expire I guess. Hope it helps - happy to jump on a call some time if you want to pair debug.

@adamjmcgrath
Copy link
Contributor

adamjmcgrath commented Sep 14, 2023

@PorridgeBear - I'd rather you created a separate issue, but thanks for sharing your HAR file

This is straight forward to debug, if you look at your error message it says:

Missing state cookie from login request (check login URL, callback URL and cookie config)

If I check the login URL from your HAR file it is: http://localhost:3000/api/auth/login
If I check the callback URL from your HAR file it is: http://gladpay.localhost:3000/api/auth/callback

localhost:3000 is a different host than gladpay.localhost:3000, you can't expect a cookie dropped on localhost:3000 to be read by gladpay.localhost:3000 - therefore you can't expect the state cookie from your login request to be read by your callback request (hence, you get a "Missing state cookie from login request" error)

@pkpjpm
Copy link

pkpjpm commented Sep 14, 2023

I had the same issue, but I fixed it by upgrading from Node 18.0.0 to 20.6.1

For the record, here's the behavior I observed:

  • From the chrome network tab, it was clear that the login handler is not setting the auth_verification cookie, so there was no way for the callback handler to pick it up
  • Tracing through the code, it was clear that the loginHandler was adding auth_verification to the returned NextRequest, but that did not result in a Set-Cookie header being added - the SendRequest method was ignoring the cookie collection
  • I suspect the production build behavior may have been different, but I was not able to build my app locally, that's what led me to realize Node was the problem. But it would also explain why only local development was affected

Just posting here in case it helps - upgrading node was the fix for me

@jmsherry
Copy link
Author

@pkpjpm Thank you!

Yes, I just realised why mine worked and then didn't (a reset of terminal changed my node version back to 18). Odd thing is that on vercel it runs on 18 (although I've not dared log out!).

I've also switched to turbopack to avoid the Ensure error listed above!

@PorridgeBear
Copy link

PorridgeBear commented Sep 15, 2023

@PorridgeBear - I'd rather you created a separate issue, but thanks for sharing your HAR file

This is straight forward to debug, if you look at your error message it says:

Missing state cookie from login request (check login URL, callback URL and cookie config)

If I check the login URL from your HAR file it is: http://localhost:3000/api/auth/login If I check the callback URL from your HAR file it is: http://gladpay.localhost:3000/api/auth/callback

localhost:3000 is a different host than gladpay.localhost:3000, you can't expect a cookie dropped on localhost:3000 to be read by gladpay.localhost:3000 - therefore you can't expect the state cookie from your login request to be read by your callback request (hence, you get a "Missing state cookie from login request" error)

OK that does makes sense, I missed that Initiator column.

However, the target for that initiated request in the HAR is the auth0 /authorize endpoint, which is buried inside this library at: export const GET = handleAuth();

My initiation of login is only ever from the custom local domain gladpay.localhost:3000

<a
        className="btn btn-primary mb-4"
        href="/api/auth/login?returnTo=/dashboard"
      >
  Sign in
</a>

So I'm not sure where localhost is coming from, I can only assume the internals of this library. I will see if I can find it but perhaps there is a bug here around not respecting custom localhost domains as the env has AUTH0_BASE_URL="http://gladpay.localhost:3000"

@cyber-nic
Copy link

cyber-nic commented Sep 15, 2023

Works on node 18.17.1 (latest LTS as of now) but fails with reported error on 18.2.0 (what I had on hand). Also works on 20.x.y as suggested.

thanks @jmsherry for reporting this and @pkpjpm a solution.

@adamjmcgrath
Copy link
Contributor

Yep - @jmsherry - apologies, I never tested your app in Node v18.1.0 (I was using v18.17). I've tested your application in 18.1.0 and can reproduce the issue. The issue is a problem with Next.js (I think more specifically it's this issue nodejs/undici#1262 that is affecting Next.js). You can't set cookies in api routes in Next with Node 18.0.0 - 18.2.0 (18.3.0 works)

You can confirm this by creating a simple API route and observing that the response does not include the set cookie header, eg

// pages/api/hello.js
export default function handler(req, res) {
  res.setHeader('Set-Cookie', 'foo=bar')
  res.status(200).json({ name: 'John Does' })
}

The response of /api/hello doesn't have a Set-Cookie header when running on Node v18.2.0, but does have the correct Set-Cookie header when running on Node v18.3.0 (which includes @nodejs/undici@5.4.0 - which includes nodejs/undici#1262)

Will see if I can raise a bug on Next.js or at least add an advisory to this SDK

@adamjmcgrath
Copy link
Contributor

It also works in next@13.4.12 and doesn't work in next@13.4.13 - so I think it's related to this open issue on Next.js vercel/next.js#53936

@adamjmcgrath
Copy link
Contributor

From my testing, this looks like it was fixed in next@13.4.20-canary.24 (although I can't see anything that might suggest this in the changelog https://github.com/vercel/next.js/releases/tag/v13.4.20-canary.24)

So the affected Node/Next combinations are:

Node 18.0.0-18.3.0 (19.6.1 throws error when you try to set cookies)
Next 13.4.13-13.4.20-canary.23

@adamjmcgrath
Copy link
Contributor

although I can't see anything that might suggest this in the changelog vercel/next.js@v13.4.20-canary.24 (release)

Must be vercel/next.js#54813 - it fixed a bunch of regressions that were introduced in next@13.4.13

@jmsherry
Copy link
Author

@adamjmcgrath Unless there's other stuff todo on here shall I close the issue?

@adamjmcgrath
Copy link
Contributor

Will close - thanks for raising this @jmsherry!

@ryanhefner
Copy link

ryanhefner commented Sep 20, 2023

@adamjmcgrath We have been trying to test authentication passing between two preview builds of different apps–hosted on Vercel–and setting AUTH0_COOKIE_DOMAIN on both of those apps to .vercel.app is causing both the Missing state cookie issue. I have also deployed the example-app to Vercel with the AUTH0_COOKIE_DOMAIN and am getting a 400 response after authenticating with the exact same error in the logs.

Any idea why simply adding the AUTH0_COOKIE_DOMAIN would cause issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

9 participants