[GH-ISSUE #2434] nextCookies() do not set Cookies with auth.api #26514

Closed
opened 2026-04-17 17:07:48 -05:00 by GiteaMirror · 11 comments
Owner

Originally created by @drago1520 on GitHub (Apr 25, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/2434

Originally assigned to: @ping-maxwell on GitHub.

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

I cannot log in with server methods like auth.api because they do not set the cookie headers in my Chrome browser on Next.js. Retrieving the session always returns null. I am using nextCookie(), but the server methods do not work. I can see Better-auth creating new sessions and users in the DB, but no cookies are returned to my browser.

Goal: Create a user on the server.

  1. I am using Next.js
  2. I followed the installation instructions for better-auth
  3. I have the nextCookie() plugin enabled
  4. Here is my call in an isolated RSC page:
import { auth } from '@/lib/auth';
import { headers } from 'next/headers';

export default async function BlogLayout({ children }: { children: React.ReactNode }) {
  const session = await auth.api.getSession({ headers: await headers() });
  console.log('session :', session);
  if (!session) {
    const data = await auth.api.signUpEmail({
        body: {
            email: `${crypto.randomUUID()}@example.com`,
            password: crypto.randomUUID(),
            name: crypto.randomUUID(),
        },
        headers: await headers(),
    });
    console.log('data :', data); //Creates users successfully; I see in the log & db.
    const session = await auth.api.getSession({ headers: await headers() });
    console.log('session :', session); //!Reads null even when I refresh the page
  }

  return (
    <>
      {children}
    </>
  );
}
  1. I expect the second console.log('session :', session); //!Reads null even when I refresh the page to read the session, but it returnsnull` even when I refresh the page, and a new user is being created.
  2. Instead, no cookies are being sent to my Chrome browser

Current vs. Expected behavior

I expect Chrome to sync with the newly created user using auth.api. Instead, no cookies are being set.

What version of Better Auth are you using?

1.2.7

Provide environment information

- OS: [Windows 10]
- Browser: [Chrome]

Which area(s) are affected? (Select all that apply)

Client

Auth config (if applicable)

import { db, schema } from "@/models";
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { anonymous, openAPI } from "better-auth/plugins";
import { nextCookies } from "better-auth/next-js";

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: "pg",
    usePlural: true,
    schema,
  }),
  emailAndPassword: {
    enabled: true,
  },
  // socialProviders: {
  //   google: {
  //     clientId: process.env.AUTH_GOOGLE_ID as string,
  //     clientSecret: process.env.AUTH_GOOGLE_SECRET as string,
  //   },
  // },
  plugins: [
    openAPI(),
    anonymous(),
    nextCookies(),
  ],
  session: {
    expiresIn: 60 * 60 * 24 * 365, // 1 year
    cookieCache: {
      enabled: true,
      maxAge: 60 * 60 * 24 * 7 // 1 week session in cookie
    }
  }
});

Additional context

#2055 might have something to do with this.

Originally created by @drago1520 on GitHub (Apr 25, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/2434 Originally assigned to: @ping-maxwell on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce I cannot log in with server methods like `auth.api` because they do not set the cookie headers in my Chrome browser on Next.js. Retrieving the session always returns `null`. I am using nextCookie(), but the server methods do not work. I can see Better-auth creating new sessions and users in the DB, but no cookies are returned to my browser. **Goal:** Create a user on the server. 1. I am using Next.js 2. I followed the installation instructions for `better-auth` 3. I have the nextCookie() plugin enabled 4. Here is my call in an isolated RSC page: ```js import { auth } from '@/lib/auth'; import { headers } from 'next/headers'; export default async function BlogLayout({ children }: { children: React.ReactNode }) { const session = await auth.api.getSession({ headers: await headers() }); console.log('session :', session); if (!session) { const data = await auth.api.signUpEmail({ body: { email: `${crypto.randomUUID()}@example.com`, password: crypto.randomUUID(), name: crypto.randomUUID(), }, headers: await headers(), }); console.log('data :', data); //Creates users successfully; I see in the log & db. const session = await auth.api.getSession({ headers: await headers() }); console.log('session :', session); //!Reads null even when I refresh the page } return ( <> {children} </> ); } ``` 5. I expect the second ` console.log('session :', session); //!Reads null even when I refresh the page to read the session, but it returns `null` even when I refresh the page, and a new user is being created. 6. Instead, no cookies are being sent to my Chrome browser ### Current vs. Expected behavior I expect Chrome to sync with the newly created user using auth.api. Instead, no cookies are being set. ### What version of Better Auth are you using? 1.2.7 ### Provide environment information ```bash - OS: [Windows 10] - Browser: [Chrome] ``` ### Which area(s) are affected? (Select all that apply) Client ### Auth config (if applicable) ```typescript import { db, schema } from "@/models"; import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { anonymous, openAPI } from "better-auth/plugins"; import { nextCookies } from "better-auth/next-js"; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", usePlural: true, schema, }), emailAndPassword: { enabled: true, }, // socialProviders: { // google: { // clientId: process.env.AUTH_GOOGLE_ID as string, // clientSecret: process.env.AUTH_GOOGLE_SECRET as string, // }, // }, plugins: [ openAPI(), anonymous(), nextCookies(), ], session: { expiresIn: 60 * 60 * 24 * 365, // 1 year cookieCache: { enabled: true, maxAge: 60 * 60 * 24 * 7 // 1 week session in cookie } } }); ``` ### Additional context #2055 might have something to do with this.
GiteaMirror added the locked label 2026-04-17 17:07:48 -05:00
Author
Owner

@ping-maxwell commented on GitHub (Apr 25, 2025):

We can't set cookies in a server-component.

The nextCookies plugin is to support server-actions.

<!-- gh-comment-id:2830352835 --> @ping-maxwell commented on GitHub (Apr 25, 2025): We can't set cookies in a server-component. The `nextCookies` plugin is to support server-actions.
Author
Owner

@drago1520 commented on GitHub (Apr 25, 2025):

Is it possible to do the following? :
Only server components
layout.tsx

  1. Check for session
  2. if there is no session, start a new by creating a anonymous user
  3. Get the session on the page.tsx (or some component that needs it)

This ensures that everything about auth is handles on the server at once.

<!-- gh-comment-id:2830448555 --> @drago1520 commented on GitHub (Apr 25, 2025): Is it possible to do the following? : **Only server components** *layout.tsx* 1. Check for session 2. if there is no session, start a new by creating a anonymous user 3. Get the session on the page.tsx (or some component that needs it) This ensures that everything about auth is handles on the server at once.
Author
Owner

@ping-maxwell commented on GitHub (Apr 25, 2025):

I don't think you can do that in a server component.
Better Auth is designed with consideration of auth being called from the client, so you shouldn't need to worry about auth methods on the client by using authClient.

If you still want to use server only for auth related calls, you will need to use a server action for things like signup or other methods which may require the cookie to be sent back to the client.

<!-- gh-comment-id:2830582886 --> @ping-maxwell commented on GitHub (Apr 25, 2025): I don't think you can do that in a server component. Better Auth is designed with consideration of auth being called from the client, so you shouldn't need to worry about auth methods on the client by using authClient. If you still want to use server only for auth related calls, you will need to use a server action for things like signup or other methods which may require the cookie to be sent back to the client.
Author
Owner

@drago1520 commented on GitHub (Apr 25, 2025):

It is strange for me not being able to manage auth from the server, but I am not super in-depth on Next.js capabilities.

The real issue stems from the error handling on nextCookies() because there is none implemented for setting cookies on the server. I will do a pull request if you agree with me.

Image

<!-- gh-comment-id:2831447775 --> @drago1520 commented on GitHub (Apr 25, 2025): It is strange for me not being able to manage auth from the server, but I am not super in-depth on Next.js capabilities. The real issue stems from the error handling on nextCookies() because there is none implemented for setting cookies on the server. I will do a pull request if you agree with me. ![Image](https://github.com/user-attachments/assets/02561d28-82d2-43a9-bce6-d9948ea689d4)
Author
Owner

@ping-maxwell commented on GitHub (Apr 26, 2025):

In Nextjs, you can't send cookies from a server component.

From the Nextjs docs, emphasis on "server actions or route handlers":

Image
<!-- gh-comment-id:2831834172 --> @ping-maxwell commented on GitHub (Apr 26, 2025): In Nextjs, you can't send cookies from a server component. From the Nextjs docs, emphasis on "server actions or route handlers": <img width="672" alt="Image" src="https://github.com/user-attachments/assets/dc7e4614-4b96-40f8-914c-1697f6091632" />
Author
Owner

@drago1520 commented on GitHub (Apr 26, 2025):

Understood. Better auth cannot send cookies from RSC, so the browser is out of sync with the newly created session in the database. I will open a pull request to improve error handling.

<!-- gh-comment-id:2832062372 --> @drago1520 commented on GitHub (Apr 26, 2025): Understood. Better auth cannot send cookies from RSC, so the browser is out of sync with the newly created session in the database. I will open a pull request to improve error handling.
Author
Owner

@soyricardodev commented on GitHub (Apr 26, 2025):

Understood. Better auth cannot send cookies from RSC, so the browser is out of sync with the newly created session in the database. I will open a pull request to improve error handling.

but the way this is working is through server actions, even with RSC

The auth.api.. is using the API route handler

<!-- gh-comment-id:2832171536 --> @soyricardodev commented on GitHub (Apr 26, 2025): > Understood. Better auth cannot send cookies from RSC, so the browser is out of sync with the newly created session in the database. I will open a pull request to improve error handling. but the way this is working is through server actions, even with RSC The auth.api.. is using the API route handler
Author
Owner

@soyricardodev commented on GitHub (Apr 26, 2025):

If you want sn anon sign up for that use a client component, get the session and create the anon if user don't have nothing

Or pass the server action to a client component

Your problem is docs reading issues I think, but what's solution has you found

<!-- gh-comment-id:2832180431 --> @soyricardodev commented on GitHub (Apr 26, 2025): If you want sn anon sign up for that use a client component, get the session and create the anon if user don't have nothing Or pass the server action to a client component Your problem is docs reading issues I think, but what's solution has you found
Author
Owner

@pricetula commented on GitHub (May 16, 2025):

As @ping-maxwell mentioned issue is setting cookies in server actions does not persist them in the browser.
So one has to create an api route handler like:-

app/api/signin/route.ts

import { auth } from "@/lib/auth"
import { NextResponse } from 'next/server'

export async function POST(req: Request) {
    const body = await req.json()

    const resp = await auth.api.signInEmail({
        body,
        asResponse: true,
        headers: req.headers,
    })

    const setCookie = resp.headers.get('set-cookie')

    const response = NextResponse.json(await resp.json(), {
        status: resp.status,
    })

    if (setCookie) {
        response.headers.set('set-cookie', setCookie)
    }

    return response
}

and make request with required details email + passowrd

const resp = await fetch('/api/signin', {
          method: 'POST',
          headers: {
              'Content-Type': 'application/json',
          },
          body: JSON.stringify(values),
 })
<!-- gh-comment-id:2885871087 --> @pricetula commented on GitHub (May 16, 2025): As @ping-maxwell mentioned issue is setting cookies in server actions does not persist them in the browser. So one has to create an api route handler like:- app/api/signin/route.ts ``` import { auth } from "@/lib/auth" import { NextResponse } from 'next/server' export async function POST(req: Request) { const body = await req.json() const resp = await auth.api.signInEmail({ body, asResponse: true, headers: req.headers, }) const setCookie = resp.headers.get('set-cookie') const response = NextResponse.json(await resp.json(), { status: resp.status, }) if (setCookie) { response.headers.set('set-cookie', setCookie) } return response } ``` and make request with required details email + passowrd ``` const resp = await fetch('/api/signin', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(values), }) ```
Author
Owner

@Aiurvie commented on GitHub (May 17, 2025):

@pricetula

I don't know whether you have solved the issuer's problem.

I know you have solved my problem.😆

Thank you very much.❤

Good morning, good afternoon and good night.🌞

<!-- gh-comment-id:2888532264 --> @Aiurvie commented on GitHub (May 17, 2025): @pricetula I don't know whether you have solved the issuer's problem. I know you have solved my problem.😆 Thank you very much.❤ Good morning, good afternoon and good night.🌞
Author
Owner

@pricetula commented on GitHub (May 18, 2025):

@Aiurvie You're welcomed, I think @drago1520 logic to create a user should be moved to api route handler and not on server component

<!-- gh-comment-id:2889169041 --> @pricetula commented on GitHub (May 18, 2025): @Aiurvie You're welcomed, I think @drago1520 logic to create a user should be moved to api route handler and not on server component
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#26514