vercel / next.js

The React Framework
https://nextjs.org
MIT License
125.12k stars 26.73k forks source link

cookies are empty in GET Route Handler is called when running with Node 18 #52209

Open ky1ejs opened 1 year ago

ky1ejs commented 1 year ago

Verify canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 22.5.0: Mon Apr 24 20:52:24 PDT 2023; root:xnu-8796.121.2~5/RELEASE_ARM64_T6000
    Binaries:
      Node: 18.2.0
      npm: 8.9.0
      Yarn: 1.22.19
      pnpm: N/A
    Relevant Packages:
      next: 13.4.9-canary.1
      eslint-config-next: 13.4.8
      react: 18.2.0
      react-dom: 18.2.0
      typescript: 5.1.6
    Next.js Config:
      output: N/A

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true)

Link to the code that reproduces this issue or a replay of the bug

https://github.com/ky1ejs/nextjs-missing-cookies-example

To Reproduce

  1. npm i & npm run dev on the example repo.
  2. Create a cookie in your browser using the developer tools
  3. Navigate to http://localhost:3000/test-cookies
  4. In your terminal you'll see middleware cookies: 1 but handler cookies: empty

Describe the Bug

Retrieving cookies in route handlers via cookies() or requests.cookies returns an empty list, despite cookies being send by the client.

Expected Behavior

Cookies passed by the client should be returned by calling cookies() or request.cookies. Instead, an empty list is returned.

Which browser are you using? (if relevant)

Arc

How are you deploying your application? (if relevant)

N/A

ky1ejs commented 1 year ago

There seems to be similar issues surrounding cookies, but not one that gives and description and example exactly like this.

joulev commented 1 year ago

It's because your code is buggy. getAll is a function for you to call, not a property where you can get an array of cookies directly.

import { cookies } from "next/headers";
import { NextResponse } from "next/server";

export async function GET() {
  const allCookies = cookies().getAll();
  console.log(
    `cookies in handler: ${allCookies.length > 0 ? allCookies.length : "empty"}`
  );
  return new NextResponse("Done", { status: 200 });
}
image
ky1ejs commented 1 year ago

@joulev whoops, my bad. Thanks!

That said, when I experienced this bug on the actual project I'm working on, I was indeed calling getAll() properly.

I just pushed this correction to the example. When running on my machine I still get:

joulev commented 1 year ago

@ky1ejs This is my output from your code. No modifications.

image

which makes sense since you are trying to print a function, obviously it will give something like function toString() { [native code] }. But it doesn't give empty. Please check again.

next info output Operating System: Platform: linux Arch: x64 Version: #48-Ubuntu SMP Tue Jun 20 20:34:08 UTC 2023 Binaries: Node: 20.3.0 npm: 9.6.7 Yarn: 1.22.19 pnpm: 8.6.2 Relevant Packages: next: 13.4.9-canary.1 eslint-config-next: 13.4.8 react: 18.2.0 react-dom: 18.2.0 typescript: 5.1.6 Next.js Config: output: N/A
ky1ejs commented 1 year ago

@joulev Did you pull the latest commit on the example repo? https://github.com/ky1ejs/nextjs-missing-cookies-example/commit/eac589a12ba4a6756dda9f4ac2a03dcc9173ee90.

It seems like you didn’t.

As I said, I fixed the bug you pointed out and pushed it to the example repo. Even when calling getAll(), I don’t get any cookies in the handler as shown in the screenshot above.

joulev commented 1 year ago

@ky1ejs

image
ky1ejs commented 1 year ago

@joulev ah... 🤦🏼 . I also forgot the parentheses on toString. Fixed and pushed.

Nonetheless... it seems that you are indeed getting cookies your Route Handler but I am not. I'm never hitting that toString() call since allCookies is empty for me.

How can the same repo produce different results for us?

I just tried clearing the /.next dir and re-installing node_modules but I get the same result.

I noticed you're on Node 20 and I'm on Node 18, I wonder if that has anything to do with it?

Screenshot

ky1ejs commented 1 year ago

FIXED! Upgraded to Node 20.3.1 and I now get cookies in the Route Handler.

So something is wrong with Node 18 + NextJS 13.

Feel free to close unless you want to track that.

Screenshot 2023-07-05 at 08 57 40
joulev commented 1 year ago

@ky1ejs Hmm no, then it is indeed a bug. Maybe it's worth to edit the title and description to reflect that this bug is only reproducible in Node.js v18.

Do you see this in prod mode as well? Because if you can reproduce this in prod mode, it would be a very critical bug, since most hosting providers, Vercel included, only supports up to Node.js v18 right now.

ky1ejs commented 1 year ago

@joulev Good idea re: title change.

Just deployed the example repo to Vercel and thankfully the issue is not happening in prod: https://nextjs-missing-cookies-example.vercel.app/test-cookies

Screenshot 2023-07-05 at 09 26 27

Not sure which specific version of Node 18 is being used in prod tho...

ky1ejs commented 1 year ago

@joulev good news: upgrading from Node 18.2.0 to v18.16.1 fixed the issue locally for me.

Again, feel free to close if you think this is a good enough solution to this issue.

joulev commented 1 year ago

Well I'm just a contributor, I don't have higher rights than you. Let's wait for a maintainer to come and triage this issue.

jingyuyao commented 1 year ago

I just ran into a similar issue while using Next.js with supabase and I don't think this is related to node version.

Working code:

export async function GET() {
  const c = cookies();
  const supabase = createRouteHandlerClient({cookies: () => c});
  return NextResponse.json({
    objects: await fetchObjects(supabase),
  });
}
// `objects` contains result as expected.

Not working code:

export async function GET() {
  const supabase = createRouteHandlerClient({cookies});
  return NextResponse.json({
    objects: await fetchObjects(supabase),
  });
}
// `objects` contains no result!

The only difference being that the cookies() method is "invoked" in the body of the working code.

I think whatever next.js is doing to analyze whether to pass cookies along or not is not matching when cookies() is not invoked in outermost GET method body.

CarlosBalladares commented 1 year ago

I found this issue on node 16, upgraded to 18.17.0 and it is solved locally.

camwest commented 1 year ago

I hit the same snag.

Here's what I unearthed:

Middleware part:

export async function middleware(req) {
  console.log(`middleware cookies: ${req.cookies.getAll().length}`);
  const res = NextResponse.next();
  const supabase = createMiddlewareClient({ req, res });
  await supabase.auth.getSession();
  return res;
}

Route handler part:

export async function GET(request: Request) {
  const allCookies = cookies().getAll();
  console.log(
    `handler cookies: ${allCookies.length > 0 ? allCookies.length : "none"}`
  );

  return new NextResponse("Done", { status: 200 });
}

Outcome:

middleware cookies: 11
handler cookies: 3

I gave updating Node, Next and others a go.

Running Node 18.x or 20.x and Next 13.4.12

If I leave out supabase in middleware:

export async function middleware(req) {
  console.log(`middleware cookies: ${req.cookies.getAll().length}`);

  const res = NextResponse.next();
  // const supabase = createMiddlewareClient({ req, res });
  // await supabase.auth.getSession();
  return res;
}

This comes up:

middleware cookies: 11
handler cookies: 11

So, it might be a Supabase bug. Hope this aids someone.

camwest commented 1 year ago
"@supabase/auth-helpers-nextjs": "^0.7.3",
camwest commented 1 year ago

Seems it's a known issue: https://github.com/supabase/auth-helpers/issues/575

CarlosBalladares commented 1 year ago

I found this issue on node 16, upgraded to 18.17.0 and it is solved locally.

It turns out it didn't solve it.

In my case this issue occurs when the route callback that exchanges the code and verifier cookie for the session is called. For some reason sometimes it runs or makes the callback request twice. The first time it exchanges the code and clears the verifier cookie, so the second time it doesnt find the cookie and throws the error. Not sure what causes it. But i worked around it by checking if theres an active session.

imPrathamDev commented 1 year ago

Has somebody found any fix for it? Upgrading the Node version is not working for me.

vhpx commented 1 year ago

The bug is resolved if you use @supabase/auth-helpers-nextjs@0.8.1

See: https://github.com/supabase/auth-helpers/releases/tag/%40supabase/auth-helpers-nextjs%400.8.1

markovsvetlin commented 12 months ago

Still not working. Did someone resolve the issue?

leerob commented 12 months ago

@markovsvetlin can you upgrade your version of Node.js as mention above?

ChrisCosentino commented 12 months ago

@markovsvetlin I got mine working running node v18.18.0, next@13.5.2 and @supabase/auth-helpers-nextjs@0.8.1. I had a bug where I was calling the route handler from a 'use server' function and the cookies were empty in the route handler. Just make sure you are calling the route handler from a client component.

onukwilip commented 11 months ago

I came across the same issue, it's not about upgrading your Node Js version. Basically, it depends on where you are calling the API endpoint from; keep note that the server doesn't have direct access to the cookies because they are stored on the browser and are sent with a request made to an API endpoint from the client. Therefore, if you are calling the API endpoint from the client (i.e. Browser), the cookies are sent alongside the request. But, if you are calling the API endpoint from a server component or another API endpoint in your application, the cookies are not sent alongside the request, because the request is being sent from the SERVER and NOT the CLIENT! Hope this helps 🙂

AayushKarki714 commented 10 months ago

I came across the same issue, it's not about upgrading your Node Js version. Basically, it depends on where you are calling the API endpoint from; keep note that the server doesn't have direct access to the cookies because they are stored on the browser and are sent with a request made to an API endpoint from the client. Therefore, if you are calling the API endpoint from the client (i.e. Browser), the cookies are sent alongside the request. But, if you are calling the API endpoint from a server component or another API endpoint in your application, the cookies are not sent alongside the request, because the request is being sent from the SERVER and NOT the CLIENT! Hope this helps 🙂

Then how can we fix this?

sinssz commented 10 months ago

I came across the same issue, it's not about upgrading your Node Js version. Basically, it depends on where you are calling the API endpoint from; keep note that the server doesn't have direct access to the cookies because they are stored on the browser and are sent with a request made to an API endpoint from the client. Therefore, if you are calling the API endpoint from the client (i.e. Browser), the cookies are sent alongside the request. But, if you are calling the API endpoint from a server component or another API endpoint in your application, the cookies are not sent alongside the request, because the request is being sent from the SERVER and NOT the CLIENT! Hope this helps 🙂

same issue... plz... solution..

CarlosBalladares commented 10 months ago

There's now @supabase/ssr that works much better than @supabase/auth-helpers For any supabase users.

jon-emble commented 9 months ago

I came across the same issue, it's not about upgrading your Node Js version. Basically, it depends on where you are calling the API endpoint from; keep note that the server doesn't have direct access to the cookies because they are stored on the browser and are sent with a request made to an API endpoint from the client. Therefore, if you are calling the API endpoint from the client (i.e. Browser), the cookies are sent alongside the request. But, if you are calling the API endpoint from a server component or another API endpoint in your application, the cookies are not sent alongside the request, because the request is being sent from the SERVER and NOT the CLIENT! Hope this helps 🙂

same issue... plz... solution..

Also the same issue - the documentation doesn't seem to address how to actually resolve this.

360macky commented 7 months ago

I came across the same issue, it's not about upgrading your Node Js version. Basically, it depends on where you are calling the API endpoint from; keep note that the server doesn't have direct access to the cookies because they are stored on the browser and are sent with a request made to an API endpoint from the client. Therefore, if you are calling the API endpoint from the client (i.e. Browser), the cookies are sent alongside the request. But, if you are calling the API endpoint from a server component or another API endpoint in your application, the cookies are not sent alongside the request, because the request is being sent from the SERVER and NOT the CLIENT! Hope this helps 🙂

I was so close to have i18n for render content 😭...

landsman commented 7 months ago

I can confirm that I saw the same issue on the latest version (14.1.0)

gitananun commented 6 months ago

Having the same problem. In the middleware, cookies are empty

krokhale commented 6 months ago

This is an issue when requests are made from a server component, what works for me is passing along the next headers along with the requests that are made from the server component:

headers: headers()

Ideally of course next cookies should handle this condition.

IRediTOTO commented 5 months ago

I get this error with action I really don't know why, I see the action not send the cookie image

jagdishpadeliya commented 1 month ago

Any solution for calling protected api route from another api route or api route from server actions ? I do see cookies empty and Authorization as Bearer undefined.

devjiwonchoi commented 1 month ago

@jagdishpadeliya @IRediTOTO @gitananun @landsman @360macky @jon-emble @sinssz @AayushKarki714

Hey everyone, I'd love to take a look at your problem(s) and bring it to the team. Could you guys share a repro so we can confirm the case more quickly? 🙏🏻

jagdishpadeliya commented 1 month ago

Any solution for calling protected api route from another api route or api route from server actions ? I do see cookies empty and Authorization as Bearer undefined.

From server actions, you can pass cookies like

import { headers } from "next/headers";
const cookies = headers().get("Cookie");
const res= await axios({
        method: "GET",
        url,
        headers: {
          Cookie: cookies,
        },
});

& from protected route, like

export async function GET(req: NextRequest){
const cookies = req.cookies.getAll();
const res= await axios({
        method: "GET",
        url,
        headers: {
          Cookie: cookies,
        },
      });
}