secondaryStorage ttl forces re-login on users #1778

Open
opened 2026-03-13 09:02:29 -05:00 by GiteaMirror · 7 comments
Owner

Originally created by @hsab on GitHub (Aug 24, 2025).

Originally assigned to: @ping-maxwell on GitHub.

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

1- Add secondaryStorage to auth setup (I'm using Cloudflare KV)
2- Setup cookie cache of 5 minutes
3- Login
4- Wait after 5 minutes and the user will be fully logged out

Current vs. Expected behavior

Using secondaryStorage should behave similar to using the primary DB. Rather than requiring re-authentication, it should appropriately fetch and refresh user's session.

What version of Better Auth are you using?

1.3.7

System info

System:
    OS: macOS 15.5
    CPU: (8) arm64 Apple M1 Pro
    Memory: 96.05 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.13.0 - ~/.nvm/versions/node/v22.13.0/bin/node
    npm: 10.9.2 - ~/.nvm/versions/node/v22.13.0/bin/npm
    pnpm: 9.15.4 - ~/.nvm/versions/node/v22.13.0/bin/pnpm
  Browsers:
    Chrome: 139.0.7258.139
    Chrome Canary: 141.0.7373.0
    Safari: 18.5
  npmPackages:
    @react-router/dev: ^7.8.1 => 7.8.1
    @react-router/node: ^7.8.1 => 7.8.1
    @react-router/serve: ^7.8.1 => 7.8.1
    react-router: ^7.8.1 => 7.8.1
    vite: 7.1.2 => 7.1.2
    wrangler: ^4.30.0 => 4.30.0

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

Backend, Client

Auth config (if applicable)

import { betterAuth } from 'better-auth';
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { APIError } from 'better-auth/api';
import { createAuthClient as createAuthClientVanilla } from 'better-auth/client';
import { emailOTPClient } from 'better-auth/client/plugins';
import { admin, apiKey, emailOTP, organization } from 'better-auth/plugins';
import { z } from 'zod';

import { AUTH_URL, AcmeDomain, AcmeURLConfig, LoopsMailingLists } from '@acme/core';
import { dbFactory } from '@acme/db/client';
import { AcmeNodemailer } from '@acme/emails';
import AcmeMagicLinkEmail from '@acme/emails/AcmeMagicLinkEmail';
import AcmeSignupEmail from '@acme/emails/AcmeSignupEmail';

import { createLoopsClient } from './loopsClient';

const { IS_LOCALHOST } = AcmeURLConfig('API');

type SelectedEnv = Pick<Cloudflare.Env, 'DATABASE_URL' | 'GOOGLE_CLIENT_ID' | 'GOOGLE_CLIENT_SECRET' | 'RESEND_PASSWORD' | 'LOOPS_API_KEY' | 'HYPERSUPADRIVE' | 'AUTH_SECONDARY_STORAGE'>;

type AuthEnv = Omit<SelectedEnv, 'HYPERSUPADRIVE' | 'AUTH_SECONDARY_STORAGE'> & Partial<Pick<SelectedEnv, 'HYPERSUPADRIVE' | 'AUTH_SECONDARY_STORAGE'>>;

export const AuthEnvVarsParser: z.ZodType<AuthEnv> = z.object({
  DATABASE_URL: z.string({ required_error: 'DATABASE_URL is required' }),
  GOOGLE_CLIENT_ID: z.string({ required_error: 'GOOGLE_CLIENT_ID is required' }),
  GOOGLE_CLIENT_SECRET: z.string({ required_error: 'GOOGLE_CLIENT_SECRET is required' }),
  RESEND_PASSWORD: z.string({ required_error: 'RESEND_PASSWORD is required' }),
  LOOPS_API_KEY: z.string({ required_error: 'LOOPS_API_KEY is required' }),
  HYPERSUPADRIVE: z.any().optional(),
  AUTH_SECONDARY_STORAGE: z.any().optional(),
});

export const authFactory = (env: AuthEnv) => betterAuth({
  database: drizzleAdapter(dbFactory({ databaseUrl: env.HYPERSUPADRIVE?.connectionString ?? env.DATABASE_URL }), {
    provider: 'pg',
    usePlural: true,
  }),
  advanced: {
    database: {
      // database's auto generated id will be used
      generateId: false,
    },
    cookiePrefix: 'acme',
    crossSubDomainCookies: {
      enabled: true,
      domain: IS_LOCALHOST ? 'localhost' : `.${AcmeDomain}`,
    },
  },
  session: {
    cookieCache: {
      enabled: true,
      maxAge: 5 * 60, // Cache duration in seconds
    },
  },
  basePath: AUTH_URL().basePath,
  baseURL: AUTH_URL().baseURL,
  trustedOrigins(request) {
    const origin = request.headers.get('origin');

    if (origin?.includes(AcmeDomain)) {
      return [origin];
    }

    if (IS_LOCALHOST) {
      return ['*'];
    }

    return [];
  },
  socialProviders: {
    google: {
      clientId: env.GOOGLE_CLIENT_ID,
      clientSecret: env.GOOGLE_CLIENT_SECRET,
    },
  },
  ...(env.AUTH_SECONDARY_STORAGE
    ? { secondaryStorage: {
        get: async (key) => {
          console.log('Using secondary storage', key);

          return env.AUTH_SECONDARY_STORAGE!.get(key);
        },
        set: async (key, value, ttl) => {
          console.log('Adding to secondary storage', key);
          await env.AUTH_SECONDARY_STORAGE!.put(key, value, { expirationTtl: ttl });
        },
        delete: async (key) => {
          console.log('Deleting from secondary storage', key);
          await env.AUTH_SECONDARY_STORAGE!.delete(key);
        },
      } }
    : {}),
  databaseHooks: {
    user: {
      create: {
        before: async (user, _ctx) => {
          const loops = createLoopsClient(env.LOOPS_API_KEY);

          const existingAudience = await loops.findContact({ email: user.email });

          // Check if the user is invited to the app or already registered
          const userIsAlreadyOnWaitlist = existingAudience?.[0]?.userGroup === 'waitlist';
          const userIsAlreadyRegistered = existingAudience?.[0]?.userGroup === 'registered';
          const userIsAlreadyInvited = existingAudience?.[0]?.userGroup === 'invited';

          const checkError = async () => {
            const genericError = `We encountered an error while adding you to the waitlist. Please try again in a few minutes or contact us at hello@${AcmeDomain}`;

            if (!userIsAlreadyInvited && !userIsAlreadyRegistered) {
              if (userIsAlreadyOnWaitlist) {
                return `You're already on the waitlist. Keep an eye on your inbox for updates.`;
              }

              try {
                // If no matches found, create new waitlist entry
                const userGroup = 'waitlist';
                const newContact = await loops.createContact(user.email, { userGroup }, LoopsMailingLists);

                if (!newContact.success) {
                  return genericError;
                }
              }
              catch (err) {
                // Blocklists usually are caught and thrown as errors by loops
                console.error('LOOPS ERROR:', user.email, err);

                return genericError;
              }

              return `Acme is invite-only! You’re now on the waitlist. Keep an eye on your inbox for updates.`;
            }

            return undefined;
          };

          const error = await checkError();

          if (error) {
            throw new APIError(403, {
              message: error,
            });
          }

          return { data: user };
        },
        after: async (user, _ctx) => {
          const loops = createLoopsClient(env.LOOPS_API_KEY);
          const [audience] = await loops.findContact({ email: user.email });
          const needsUpdate = audience?.userGroup !== 'registered' || audience?.userId !== user.id;
          const userId = user.id;
          const userGroup = 'registered';

          try {
            if (audience && needsUpdate) {
              await loops.updateContact(user.email, { userId, userGroup }, LoopsMailingLists);
            }
            else {
              await loops.createContact(user.email, { userId, userGroup }, LoopsMailingLists);
            }
          }
          catch (error) {
            console.error(error);
            throw new APIError(400, {
              message: `Something went wrong while registering you. Please try again in a few minutes. If you need further assistance, don't hesitate to contact us at hello@${AcmeDomain}`,
            });
          }
        },
      },
    },
  },
  plugins: [
    admin(),
    apiKey(),
    organization(),
    emailOTP({
      async sendVerificationOTP({ email, otp, type }) {
        if (type === 'sign-in') {
          await AcmeNodemailer({
            to: email,
            component: AcmeMagicLinkEmail,
            props: {
              token: otp,
            },
            subject: `Your Acme login code is ${otp}`,
            resendPassword: env.RESEND_PASSWORD,
          });
          // Send the OTP for sign in
        }
        else if (type === 'email-verification') {
          await AcmeNodemailer({
            to: email,
            component: AcmeSignupEmail,
            props: {
              token: otp,
            },
            subject: `Your Acme confirmation code is ${otp}`,
            resendPassword: env.RESEND_PASSWORD,
          });
        }
        else {
          // Send the OTP for password reset
          throw new Error('Password reset not implemented');
        }
      },
    }),
  ],
});

export const auth = authFactory({
  DATABASE_URL: process.env.DATABASE_URL ?? '',
  GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID ?? '',
  GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET ?? '',
  RESEND_PASSWORD: process.env.RESEND_PASSWORD ?? '',
  LOOPS_API_KEY: process.env.LOOPS_API_KEY ?? '',
});

export type AuthData = typeof auth.$Infer.Session;
export type AuthSession = typeof auth.$Infer.Session.session;
export type AuthUser = typeof auth.$Infer.Session.user;

export const authClientServer = createAuthClientVanilla({
  baseURL: AUTH_URL().fullURL,
  plugins: [
    emailOTPClient(),
  ],
});

Additional context

No response

Originally created by @hsab on GitHub (Aug 24, 2025). Originally assigned to: @ping-maxwell on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1- Add secondaryStorage to auth setup (I'm using Cloudflare KV) 2- Setup cookie cache of 5 minutes 3- Login 4- Wait after 5 minutes and the user will be fully logged out ### Current vs. Expected behavior Using secondaryStorage should behave similar to using the primary DB. Rather than requiring re-authentication, it should appropriately fetch and refresh user's session. ### What version of Better Auth are you using? 1.3.7 ### System info ```bash System: OS: macOS 15.5 CPU: (8) arm64 Apple M1 Pro Memory: 96.05 MB / 16.00 GB Shell: 5.9 - /bin/zsh Binaries: Node: 22.13.0 - ~/.nvm/versions/node/v22.13.0/bin/node npm: 10.9.2 - ~/.nvm/versions/node/v22.13.0/bin/npm pnpm: 9.15.4 - ~/.nvm/versions/node/v22.13.0/bin/pnpm Browsers: Chrome: 139.0.7258.139 Chrome Canary: 141.0.7373.0 Safari: 18.5 npmPackages: @react-router/dev: ^7.8.1 => 7.8.1 @react-router/node: ^7.8.1 => 7.8.1 @react-router/serve: ^7.8.1 => 7.8.1 react-router: ^7.8.1 => 7.8.1 vite: 7.1.2 => 7.1.2 wrangler: ^4.30.0 => 4.30.0 ``` ### Which area(s) are affected? (Select all that apply) Backend, Client ### Auth config (if applicable) ```typescript import { betterAuth } from 'better-auth'; import { drizzleAdapter } from 'better-auth/adapters/drizzle'; import { APIError } from 'better-auth/api'; import { createAuthClient as createAuthClientVanilla } from 'better-auth/client'; import { emailOTPClient } from 'better-auth/client/plugins'; import { admin, apiKey, emailOTP, organization } from 'better-auth/plugins'; import { z } from 'zod'; import { AUTH_URL, AcmeDomain, AcmeURLConfig, LoopsMailingLists } from '@acme/core'; import { dbFactory } from '@acme/db/client'; import { AcmeNodemailer } from '@acme/emails'; import AcmeMagicLinkEmail from '@acme/emails/AcmeMagicLinkEmail'; import AcmeSignupEmail from '@acme/emails/AcmeSignupEmail'; import { createLoopsClient } from './loopsClient'; const { IS_LOCALHOST } = AcmeURLConfig('API'); type SelectedEnv = Pick<Cloudflare.Env, 'DATABASE_URL' | 'GOOGLE_CLIENT_ID' | 'GOOGLE_CLIENT_SECRET' | 'RESEND_PASSWORD' | 'LOOPS_API_KEY' | 'HYPERSUPADRIVE' | 'AUTH_SECONDARY_STORAGE'>; type AuthEnv = Omit<SelectedEnv, 'HYPERSUPADRIVE' | 'AUTH_SECONDARY_STORAGE'> & Partial<Pick<SelectedEnv, 'HYPERSUPADRIVE' | 'AUTH_SECONDARY_STORAGE'>>; export const AuthEnvVarsParser: z.ZodType<AuthEnv> = z.object({ DATABASE_URL: z.string({ required_error: 'DATABASE_URL is required' }), GOOGLE_CLIENT_ID: z.string({ required_error: 'GOOGLE_CLIENT_ID is required' }), GOOGLE_CLIENT_SECRET: z.string({ required_error: 'GOOGLE_CLIENT_SECRET is required' }), RESEND_PASSWORD: z.string({ required_error: 'RESEND_PASSWORD is required' }), LOOPS_API_KEY: z.string({ required_error: 'LOOPS_API_KEY is required' }), HYPERSUPADRIVE: z.any().optional(), AUTH_SECONDARY_STORAGE: z.any().optional(), }); export const authFactory = (env: AuthEnv) => betterAuth({ database: drizzleAdapter(dbFactory({ databaseUrl: env.HYPERSUPADRIVE?.connectionString ?? env.DATABASE_URL }), { provider: 'pg', usePlural: true, }), advanced: { database: { // database's auto generated id will be used generateId: false, }, cookiePrefix: 'acme', crossSubDomainCookies: { enabled: true, domain: IS_LOCALHOST ? 'localhost' : `.${AcmeDomain}`, }, }, session: { cookieCache: { enabled: true, maxAge: 5 * 60, // Cache duration in seconds }, }, basePath: AUTH_URL().basePath, baseURL: AUTH_URL().baseURL, trustedOrigins(request) { const origin = request.headers.get('origin'); if (origin?.includes(AcmeDomain)) { return [origin]; } if (IS_LOCALHOST) { return ['*']; } return []; }, socialProviders: { google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, }, }, ...(env.AUTH_SECONDARY_STORAGE ? { secondaryStorage: { get: async (key) => { console.log('Using secondary storage', key); return env.AUTH_SECONDARY_STORAGE!.get(key); }, set: async (key, value, ttl) => { console.log('Adding to secondary storage', key); await env.AUTH_SECONDARY_STORAGE!.put(key, value, { expirationTtl: ttl }); }, delete: async (key) => { console.log('Deleting from secondary storage', key); await env.AUTH_SECONDARY_STORAGE!.delete(key); }, } } : {}), databaseHooks: { user: { create: { before: async (user, _ctx) => { const loops = createLoopsClient(env.LOOPS_API_KEY); const existingAudience = await loops.findContact({ email: user.email }); // Check if the user is invited to the app or already registered const userIsAlreadyOnWaitlist = existingAudience?.[0]?.userGroup === 'waitlist'; const userIsAlreadyRegistered = existingAudience?.[0]?.userGroup === 'registered'; const userIsAlreadyInvited = existingAudience?.[0]?.userGroup === 'invited'; const checkError = async () => { const genericError = `We encountered an error while adding you to the waitlist. Please try again in a few minutes or contact us at hello@${AcmeDomain}`; if (!userIsAlreadyInvited && !userIsAlreadyRegistered) { if (userIsAlreadyOnWaitlist) { return `You're already on the waitlist. Keep an eye on your inbox for updates.`; } try { // If no matches found, create new waitlist entry const userGroup = 'waitlist'; const newContact = await loops.createContact(user.email, { userGroup }, LoopsMailingLists); if (!newContact.success) { return genericError; } } catch (err) { // Blocklists usually are caught and thrown as errors by loops console.error('LOOPS ERROR:', user.email, err); return genericError; } return `Acme is invite-only! You’re now on the waitlist. Keep an eye on your inbox for updates.`; } return undefined; }; const error = await checkError(); if (error) { throw new APIError(403, { message: error, }); } return { data: user }; }, after: async (user, _ctx) => { const loops = createLoopsClient(env.LOOPS_API_KEY); const [audience] = await loops.findContact({ email: user.email }); const needsUpdate = audience?.userGroup !== 'registered' || audience?.userId !== user.id; const userId = user.id; const userGroup = 'registered'; try { if (audience && needsUpdate) { await loops.updateContact(user.email, { userId, userGroup }, LoopsMailingLists); } else { await loops.createContact(user.email, { userId, userGroup }, LoopsMailingLists); } } catch (error) { console.error(error); throw new APIError(400, { message: `Something went wrong while registering you. Please try again in a few minutes. If you need further assistance, don't hesitate to contact us at hello@${AcmeDomain}`, }); } }, }, }, }, plugins: [ admin(), apiKey(), organization(), emailOTP({ async sendVerificationOTP({ email, otp, type }) { if (type === 'sign-in') { await AcmeNodemailer({ to: email, component: AcmeMagicLinkEmail, props: { token: otp, }, subject: `Your Acme login code is ${otp}`, resendPassword: env.RESEND_PASSWORD, }); // Send the OTP for sign in } else if (type === 'email-verification') { await AcmeNodemailer({ to: email, component: AcmeSignupEmail, props: { token: otp, }, subject: `Your Acme confirmation code is ${otp}`, resendPassword: env.RESEND_PASSWORD, }); } else { // Send the OTP for password reset throw new Error('Password reset not implemented'); } }, }), ], }); export const auth = authFactory({ DATABASE_URL: process.env.DATABASE_URL ?? '', GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID ?? '', GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET ?? '', RESEND_PASSWORD: process.env.RESEND_PASSWORD ?? '', LOOPS_API_KEY: process.env.LOOPS_API_KEY ?? '', }); export type AuthData = typeof auth.$Infer.Session; export type AuthSession = typeof auth.$Infer.Session.session; export type AuthUser = typeof auth.$Infer.Session.user; export const authClientServer = createAuthClientVanilla({ baseURL: AUTH_URL().fullURL, plugins: [ emailOTPClient(), ], }); ``` ### Additional context _No response_
GiteaMirror added the bug label 2026-03-13 09:02:29 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Aug 24, 2025):

Hi @hsab! I'm Dosu and I’m helping the better-auth team.

This behavior is likely due to how Better Auth handles session fallback when the cookie cache expires. Normally, after the cookie cache TTL, the system should fetch and refresh the session from secondaryStorage or the primary DB, but if the fallback logic is missing or misconfigured, it can force a logout instead of refreshing the session as expected. This issue has been reported before, especially when using both customSession and cookieCache, where the session_token cookie isn't refreshed, leading to forced re-authentication even if the session is still valid in secondaryStorage or the DB [source].

To work around this, you can:

  • Use the disableCookieCache query parameter on your getSession calls to force a fresh fetch from secondaryStorage or DB, which will refresh the session_token cookie and avoid forced logout.
  • Try disabling cookieCache entirely to see if the issue persists. If disabling cookieCache resolves the problem, it's a strong indicator that the issue is with cookie-based session caching, not your secondaryStorage setup [source].
  • Consider setting storeSessionInDatabase: true in your session config. This ensures session persistence in the DB even when secondaryStorage is used, which can help maintain session state beyond the cookie cache TTL [source].

Recent versions of Better Auth have fixed related bugs, so upgrading may also help if you're not already on the latest release. If you have custom session logic, double-check that it isn't interfering with session reads/writes.

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 (Aug 24, 2025): <!-- Greeting --> Hi @hsab! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This behavior is likely due to how Better Auth handles session fallback when the cookie cache expires. Normally, after the cookie cache TTL, the system should fetch and refresh the session from secondaryStorage or the primary DB, but if the fallback logic is missing or misconfigured, it can force a logout instead of refreshing the session as expected. This issue has been reported before, especially when using both customSession and cookieCache, where the session_token cookie isn't refreshed, leading to forced re-authentication even if the session is still valid in secondaryStorage or the DB [[source]](https://github.com/better-auth/better-auth/issues/3713). To work around this, you can: - Use the `disableCookieCache` query parameter on your `getSession` calls to force a fresh fetch from secondaryStorage or DB, which will refresh the session_token cookie and avoid forced logout. - Try disabling cookieCache entirely to see if the issue persists. If disabling cookieCache resolves the problem, it's a strong indicator that the issue is with cookie-based session caching, not your secondaryStorage setup [[source]](https://github.com/better-auth/better-auth/issues/3462#issuecomment-3091962612). - Consider setting `storeSessionInDatabase: true` in your session config. This ensures session persistence in the DB even when secondaryStorage is used, which can help maintain session state beyond the cookie cache TTL [[source]](https://github.com/better-auth/better-auth/issues/2007#issuecomment-2897117162). Recent versions of Better Auth have fixed related bugs, so upgrading may also help if you're not already on the latest release. If you have custom session logic, double-check that it isn't interfering with session reads/writes. <!-- 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/32c980fe-fb7d-417d-bb14-dcbea41491c4?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/32c980fe-fb7d-417d-bb14-dcbea41491c4?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/32c980fe-fb7d-417d-bb14-dcbea41491c4?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/32c980fe-fb7d-417d-bb14-dcbea41491c4?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/32c980fe-fb7d-417d-bb14-dcbea41491c4?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/32c980fe-fb7d-417d-bb14-dcbea41491c4?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/32c980fe-fb7d-417d-bb14-dcbea41491c4?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/4203)
Author
Owner
@himself65 commented on GitHub (Aug 25, 2025): related PR: https://github.com/better-auth/better-auth/pull/3890 https://github.com/better-auth/better-auth/pull/3795
Author
Owner

@ping-maxwell commented on GitHub (Oct 3, 2025):

@hsab can you confirm this is still an issue on latest?

@ping-maxwell commented on GitHub (Oct 3, 2025): @hsab can you confirm this is still an issue on latest?
Author
Owner

@hsab commented on GitHub (Oct 3, 2025):

@ping-maxwell I can give it a try and report back. Do I need to make any modifications to my existing code or is this plug an play?

@hsab commented on GitHub (Oct 3, 2025): @ping-maxwell I can give it a try and report back. Do I need to make any modifications to my existing code or is this plug an play?
Author
Owner

@ping-maxwell commented on GitHub (Oct 4, 2025):

Just make sure you're on the latest version and check

@ping-maxwell commented on GitHub (Oct 4, 2025): Just make sure you're on the latest version and check
Author
Owner

@ping-maxwell commented on GitHub (Oct 21, 2025):

Closing this issue as no response was provided. Happy to re-open as needed.

@ping-maxwell commented on GitHub (Oct 21, 2025): Closing this issue as no response was provided. Happy to re-open as needed.
Author
Owner

@alsguimaraes commented on GitHub (Jan 3, 2026):

@ping-maxwell
I was able to test this today, with latest canary and also with 1.4.10.
If secondary storage is enabled, the session is lost after 5 minutes.

@alsguimaraes commented on GitHub (Jan 3, 2026): @ping-maxwell I was able to test this today, with latest canary and also with 1.4.10. If secondary storage is enabled, the session is lost after 5 minutes.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#1778