Cookie cache not updated from auth.api.getSession (Tanstack-Start) #1832

Closed
opened 2026-03-13 09:06:36 -05:00 by GiteaMirror · 11 comments
Owner

Originally created by @dannylin108 on GitHub (Sep 3, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

I see session_data cookie set after sign-in, but after it expires, subsequent successful calls of auth.api.getSession in server-function or middle-ware don't set the cookie again.

A workaround proposed the by the bot (https://github.com/better-auth/better-auth/discussions/4231) is to call getSession({header, asRequest: true }) and then set the cookies manually:

// Use asResponse:true to ensure cookies are set by Better Auth
        const res = await auth?.api.getSession({ headers, asResponse: true });
        let data: Session | null = null;
        let user: SessionUser | null = null;
        if (res && res instanceof Response) {
            try {
                data = await res.json() as Session | null;
                user = data?.user ?? null;
            } catch {
                console.error('authRedirect> failed to parse session', res);
            }
            if (user) {
                applyResponseCookies(res);
            }
        }

// ----

function applyResponseCookies(res: Response) {
    const cookieList = res.headers.getSetCookie();

    if (!cookieList?.length) return;

    for (const cookieStr of cookieList) {
    // ....
       setCookie(name, value, opts);
    }
}

but it's kinda weird, plus before, I remember, it was working seamlessly. So it's a newly introduced bug.

Current vs. Expected behavior

I expect that after one hour according to my settings, auth.api.getSession called from server function or middleware will set session_data cookie, but it doesn't happen.

What version of Better Auth are you using?

1.3.7

System info

System:
    OS: Linux 6.12 cpe:/o:nixos:nixos:25.05 25.05 (Warbler)
    CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz
    Memory: 5.43 GB / 15.32 GB
    Container: Yes
    Shell: 5.9 - /run/current-system/sw/bin/zsh
  Browsers:
    Brave Browser: 139.1.81.136
    Chromium: 139.0.7258.154

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

Client, Backend

Auth config (if applicable)

export const auth = betterAuth({
    database: drizzleAdapter(getDb(), {
        provider: "sqlite",
        schema: {
            ...authSchema,
        },
        usePlural: true
    }),
    plugins: [
        tgAuthPlugin(),
        reactStartCookies()
    ],
    session: {
        cookieCache: {
            enabled: true,
            maxAge: 60 * 60 * 1 // 1 hour, will be updated in middleware
        },
        expiresIn: TEN_DAYS_IN_SECONDS, 
        updateAge: 60 * 60 * 24, // 1 day
    },

});

Additional context

No response

Originally created by @dannylin108 on GitHub (Sep 3, 2025). ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce I see `session_data` cookie set after sign-in, but after it expires, subsequent successful calls of `auth.api.getSession` in server-function or middle-ware don't set the cookie again. A workaround proposed the by the bot (https://github.com/better-auth/better-auth/discussions/4231) is to call `getSession({header, asRequest: true })` and then set the cookies manually: ```ts // Use asResponse:true to ensure cookies are set by Better Auth const res = await auth?.api.getSession({ headers, asResponse: true }); let data: Session | null = null; let user: SessionUser | null = null; if (res && res instanceof Response) { try { data = await res.json() as Session | null; user = data?.user ?? null; } catch { console.error('authRedirect> failed to parse session', res); } if (user) { applyResponseCookies(res); } } // ---- function applyResponseCookies(res: Response) { const cookieList = res.headers.getSetCookie(); if (!cookieList?.length) return; for (const cookieStr of cookieList) { // .... setCookie(name, value, opts); } } ``` but it's kinda weird, plus before, I remember, it was working seamlessly. So it's a newly introduced bug. ### Current vs. Expected behavior I expect that after one hour according to my settings, `auth.api.getSession` called from server function or middleware will set `session_data` cookie, but it doesn't happen. ### What version of Better Auth are you using? 1.3.7 ### System info ```bash System: OS: Linux 6.12 cpe:/o:nixos:nixos:25.05 25.05 (Warbler) CPU: (8) x64 11th Gen Intel(R) Core(TM) i7-1165G7 @ 2.80GHz Memory: 5.43 GB / 15.32 GB Container: Yes Shell: 5.9 - /run/current-system/sw/bin/zsh Browsers: Brave Browser: 139.1.81.136 Chromium: 139.0.7258.154 ``` ### Which area(s) are affected? (Select all that apply) Client, Backend ### Auth config (if applicable) ```typescript export const auth = betterAuth({ database: drizzleAdapter(getDb(), { provider: "sqlite", schema: { ...authSchema, }, usePlural: true }), plugins: [ tgAuthPlugin(), reactStartCookies() ], session: { cookieCache: { enabled: true, maxAge: 60 * 60 * 1 // 1 hour, will be updated in middleware }, expiresIn: TEN_DAYS_IN_SECONDS, updateAge: 60 * 60 * 24, // 1 day }, }); ``` ### Additional context _No response_
GiteaMirror added the bugtanstack-start labels 2026-03-13 09:06:36 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Sep 3, 2025):

This is expected behavior in Better Auth v1.3.7 when using TanStack Start middleware or server functions: calling auth.api.getSession({ headers }) alone does not update the session_data cookie after it expires. To trigger a cookie update, you need to call getSession with asResponse: true (or returnHeaders: true), then extract and forward the set-cookie header to the client—just like in the workaround you referenced. This is necessary because, in these server contexts, cookies are only set if the response object is explicitly handled and propagated by your code or middleware. This approach is now the recommended and documented way to handle session cookie renewal in these environments see discussion see issue.

This change is not a bug but a result of how cookie propagation works in server-side code paths: automatic renewal only happens if the response is managed in "response mode" (with asResponse: true). If you want the old seamless behavior, you’d need to ensure your middleware or server function always forwards the set-cookie header from the response returned by getSession.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

@dosubot[bot] commented on GitHub (Sep 3, 2025): <!-- Answer --> This is expected behavior in Better Auth v1.3.7 when using TanStack Start middleware or server functions: calling `auth.api.getSession({ headers })` alone does not update the `session_data` cookie after it expires. To trigger a cookie update, you need to call `getSession` with `asResponse: true` (or `returnHeaders: true`), then extract and forward the `set-cookie` header to the client—just like in the workaround you referenced. This is necessary because, in these server contexts, cookies are only set if the response object is explicitly handled and propagated by your code or middleware. This approach is now the recommended and documented way to handle session cookie renewal in these environments [see discussion](https://github.com/better-auth/better-auth/discussions/4231) [see issue](https://github.com/better-auth/better-auth/issues/3780). This change is not a bug but a result of how cookie propagation works in server-side code paths: automatic renewal only happens if the response is managed in "response mode" (with `asResponse: true`). If you want the old seamless behavior, you’d need to ensure your middleware or server function always forwards the `set-cookie` header from the response returned by `getSession`. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/6ee49b60-37be-4901-a4a6-ad94ac20d488?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/6ee49b60-37be-4901-a4a6-ad94ac20d488?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/6ee49b60-37be-4901-a4a6-ad94ac20d488?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/6ee49b60-37be-4901-a4a6-ad94ac20d488?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/6ee49b60-37be-4901-a4a6-ad94ac20d488?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/6ee49b60-37be-4901-a4a6-ad94ac20d488?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/6ee49b60-37be-4901-a4a6-ad94ac20d488?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/4389)
Author
Owner

@LonJonn commented on GitHub (Oct 8, 2025):

The reactStartCookies() plugin doesn't work properly. I just copied it's source I swapped out the cookie set calls with the ones from tanstack start directly:

import { setCookie } from "@tanstack/react-start/server";
import { parseSetCookieHeader } from "better-auth/cookies";

function autoCookies(): BetterAuthPlugin {
  return {
    id: "auto-cookies",
    hooks: {
      after: [
        {
          matcher(_ctx) {
            return true;
          },
          handler: createAuthMiddleware(async (ctx) => {
            const returned = ctx.context.responseHeaders;
            if ("_flag" in ctx && ctx._flag === "router") {
              return;
            }
            if (returned instanceof Headers) {
              const setCookies = returned?.get("set-cookie");
              if (!setCookies) {
                return;
              }
              const parsed = parseSetCookieHeader(setCookies);
              parsed.forEach((value, key) => {
                if (!key) {
                  return;
                }
                const opts = {
                  sameSite: value.samesite,
                  secure: value.secure,
                  maxAge: value["max-age"],
                  httpOnly: value.httponly,
                  domain: value.domain,
                  path: value.path,
                };

                setCookie(key, decodeURIComponent(value.value), opts);
              });
              return;
            }
          }),
        },
      ],
    },
  };
}

And now you can use this in place of reactStartCookies()

@LonJonn commented on GitHub (Oct 8, 2025): The reactStartCookies() plugin doesn't work properly. I just copied it's source I swapped out the cookie set calls with the ones from tanstack start directly: ```ts import { setCookie } from "@tanstack/react-start/server"; import { parseSetCookieHeader } from "better-auth/cookies"; function autoCookies(): BetterAuthPlugin { return { id: "auto-cookies", hooks: { after: [ { matcher(_ctx) { return true; }, handler: createAuthMiddleware(async (ctx) => { const returned = ctx.context.responseHeaders; if ("_flag" in ctx && ctx._flag === "router") { return; } if (returned instanceof Headers) { const setCookies = returned?.get("set-cookie"); if (!setCookies) { return; } const parsed = parseSetCookieHeader(setCookies); parsed.forEach((value, key) => { if (!key) { return; } const opts = { sameSite: value.samesite, secure: value.secure, maxAge: value["max-age"], httpOnly: value.httponly, domain: value.domain, path: value.path, }; setCookie(key, decodeURIComponent(value.value), opts); }); return; } }), }, ], }, }; } ``` And now you can use this in place of reactStartCookies()
Author
Owner

@dannylin108 commented on GitHub (Oct 9, 2025):

@LonJonn , yes, that's the solution, thanks a lot!

@dannylin108 commented on GitHub (Oct 9, 2025): @LonJonn , yes, that's the solution, thanks a lot!
Author
Owner

@jsa4000 commented on GitHub (Oct 10, 2025):

@LonJonn awesome! that's works, now using all auth.api.*, etc.. work with cookies.

@jsa4000 commented on GitHub (Oct 10, 2025): @LonJonn awesome! that's works, now using all auth.api.*, etc.. work with cookies.
Author
Owner

@Gallevy commented on GitHub (Oct 12, 2025):

@LonJonn where is createAuthMiddleware imported from, its not available for me even if i install @better-auth/core

Edit: Found it, i was confused about the default branch which is canary which changed where it was located

@Gallevy commented on GitHub (Oct 12, 2025): @LonJonn where is `createAuthMiddleware` imported from, its not available for me even if i install `@better-auth/core` Edit: Found it, i was confused about the default branch which is canary which changed where it was located
Author
Owner

@uriafranko commented on GitHub (Nov 8, 2025):

for some reason I still get empty set-cookie also the parsed is empty

List of plugins:

      lastLoginMethod(),
      organization(),
      apiKey({
        enableSessionForAPIKeys: true,
        apiKeyHeaders: ["x-api-key"],
        enableMetadata: true,
        rateLimit: {
          enabled: true,
          maxRequests: 100,
          timeWindow: 60 * 1000, // 1 minute
        },
      }),
      autoCookies(),
    ],
@uriafranko commented on GitHub (Nov 8, 2025): for some reason I still get empty set-cookie also the parsed is empty List of plugins: ``` plugins: [ lastLoginMethod(), organization(), apiKey({ enableSessionForAPIKeys: true, apiKeyHeaders: ["x-api-key"], enableMetadata: true, rateLimit: { enabled: true, maxRequests: 100, timeWindow: 60 * 1000, // 1 minute }, }), autoCookies(), ], ```
Author
Owner

@dannylin108 commented on GitHub (Dec 9, 2025):

Seems fixed in 1.4+

@dannylin108 commented on GitHub (Dec 9, 2025): Seems fixed in 1.4+
Author
Owner

@jsa4000 commented on GitHub (Dec 9, 2025):

Hi, @dannylin108. how do you make it work? In my case using newest versions from 1.4.X do not solve the problem at all and the cookie is not being set in the server. I am still using the code provided by @LonJonn

Thanks in advance.

@jsa4000 commented on GitHub (Dec 9, 2025): Hi, @dannylin108. how do you make it work? In my case using newest versions from 1.4.X do not solve the problem at all and the cookie is not being set in the server. I am still using the code provided by @LonJonn Thanks in advance.
Author
Owner

@jrdn91 commented on GitHub (Jan 15, 2026):

This still does not resolve the issue for me. I am on 1.4.10 of better-auth. Sessions are being created in my database, but no session token is being stored as a cookie in the browser, so I can't use any of the methods to get the session as there is no token to be referenced.

@jrdn91 commented on GitHub (Jan 15, 2026): This still does not resolve the issue for me. I am on 1.4.10 of better-auth. Sessions are being created in my database, but no session token is being stored as a cookie in the browser, so I can't use any of the methods to get the session as there is no token to be referenced.
Author
Owner

@jrdn91 commented on GitHub (Jan 16, 2026):

This still does not resolve the issue for me. I am on 1.4.10 of better-auth. Sessions are being created in my database, but no session token is being stored as a cookie in the browser, so I can't use any of the methods to get the session as there is no token to be referenced.

I saw in the Better Auth discord a node from a user that Tan Stack needs node v22 and that they were on node v20 (I was in the same boat) and changing to node v22 fixed the isssue. I can confirm this has resolve the issue, and I can use the built in plugin. Here is the comment if you have joined the Better Auth discord

https://discord.com/channels/1288403910284935179/1460284624038006865/1460293179155939389

@jsa4000 thi might help you if you are still stuck on this

@jrdn91 commented on GitHub (Jan 16, 2026): > This still does not resolve the issue for me. I am on 1.4.10 of better-auth. Sessions are being created in my database, but no session token is being stored as a cookie in the browser, so I can't use any of the methods to get the session as there is no token to be referenced. I saw in the Better Auth discord a node from a user that Tan Stack needs node v22 and that they were on node v20 (I was in the same boat) and changing to node v22 fixed the isssue. I can confirm this has resolve the issue, and I can use the built in plugin. Here is the comment if you have joined the Better Auth discord https://discord.com/channels/1288403910284935179/1460284624038006865/1460293179155939389 @jsa4000 thi might help you if you are still stuck on this
Author
Owner

@nachomglz commented on GitHub (Feb 5, 2026):

I'm a bit lost on this issue, I'm not using tanstack for anything, I have a next.js app and a separate fastify server holding the better auth server.

I have cookieCache enabled, and when I do await getSession({ query: { disableCookieCache: true} }) from the server client (created using better-auth/client's crateAuthClient method) it returns the updated session (the one in the database) but it doesn't refresh the cookie, but when I do the same call from a client component or from any other http client - it does refresh the cookie even for the calls from the server.

This is extremely confusing and I still don't really understand what the issue is.

Does this mean that we can't - at all - handle sessions on the server without relying on the client to refresh the cookies?

@nachomglz commented on GitHub (Feb 5, 2026): I'm a bit lost on this issue, I'm not using tanstack for anything, I have a next.js app and a separate fastify server holding the better auth server. I have cookieCache enabled, and when I do `await getSession({ query: { disableCookieCache: true} })` from the server client (created using `better-auth/client`'s `crateAuthClient` method) it returns the updated session (the one in the database) but it doesn't refresh the cookie, but when I do the same call from a client component or from any other http client - it does refresh the cookie even for the calls from the server. This is extremely confusing and I still don't really understand what the issue is. Does this mean that we can't - at all - handle sessions on the server without relying on the client to refresh the cookies?
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#1832