Bug: Login does not maintain session with production API and local front-end #2297

Closed
opened 2026-03-13 09:42:14 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @viniimartins on GitHub (Nov 13, 2025).

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Description:
When the front-end is running locally (http://localhost:3000) and the API is in production, attempting to log in appears to work, but nothing happens: the session is not created or maintained, and the user state does not change on the front-end.

Note:
The production front-end (app.meudominio.com) works correctly with the same API.

Configuration used:

import { env } from '@config/env';
import { typeormAdapter } from '@hedystia/better-auth-typeorm';
import { betterAuth } from 'better-auth';
import { bearer, openAPI } from 'better-auth/plugins';
import { DataSourceManager } from 'db/typeorm/database-connection';
import { UserRole } from '../../users/entities/user.entity';

const LOCAL_FRONTEND = 'http://localhost:3000';

export const BetterAuthConfig = betterAuth({
  secret: env.ACCESS_TOKEN_SECRET,
  emailAndPassword: { enabled: true, autoSignIn: false },
  socialProviders: {
    google: {
      clientId: env.GOOGLE_CLIENT_ID,
      clientSecret: env.GOOGLE_CLIENT_SECRET,
      redirectURI: `${env.NEXT_PUBLIC_APP_BASE_URL}/api/auth/callback/google`,
    },
  },
  trustedOrigins: [env.NEXT_PUBLIC_APP_BASE_URL, LOCAL_FRONTEND],
  user: {
    modelName: 'users',
    additionalFields: {
      role: { type: 'string', enum: UserRole, default: UserRole.MEMBER, input: false },
    },
  },
  session: { modelName: 'sessions' },
  verification: { modelName: 'verifications' },
  account: { modelName: 'accounts' },
  advanced: {
    database: { generateId: false },
    crossSubDomainCookies: {
      enabled: env.NODE_ENV === 'production',
      domain: env.NODE_ENV === 'production' ? '.meudominio.com' : undefined,
    },
    cookiePrefix: 'ah',
    useSecureCookies: env.NODE_ENV === 'production',
  },
  database: typeormAdapter(DataSourceManager),
  plugins: [bearer(), openAPI()],
});

Question:
How can BetterAuth be configured so that the local front-end can authenticate with the production API and maintain the session, without affecting the production front-end?

Current vs. Expected behavior

Current Behavior:
When logging in from the local front-end (http://localhost:3000) against the production API, the login appears to succeed, but no session is created or maintained. The user state does not update, and nothing happens on the front-end.

Expected Behavior:
The local front-end should successfully authenticate with the production API and maintain the session, just like the production front-end (app.meudominio.com) does.

Note:
Providing incomplete or missing information may result in the issue being closed.

What version of Better Auth are you using?

1.3.7

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 25.0.0: Wed Sep 17 21:42:08 PDT 2025; root:xnu-12377.1.9~141/RELEASE_ARM64_T8132",
    "release": "25.0.0",
    "cpuCount": 10,
    "cpuModel": "Apple M4",
    "totalMemory": "16.00 GB",
    "freeMemory": "0.96 GB"
  },
  "node": {
    "version": "v22.21.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.9.4"
  },
  "frameworks": null,
  "databases": [
    {
      "name": "pg",
      "version": "^8.16.3"
    }
  ],
  "betterAuth": {
    "version": "^1.3.7",
    "config": null
  }
}

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

Backend

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
});

Additional context

No response

Originally created by @viniimartins on GitHub (Nov 13, 2025). ### Is this suited for github? - [ ] Yes, this is suited for github ### To Reproduce Description: When the front-end is running locally (http://localhost:3000) and the API is in production, attempting to log in appears to work, but nothing happens: the session is not created or maintained, and the user state does not change on the front-end. Note: The production front-end (app.meudominio.com) works correctly with the same API. Configuration used: ``` import { env } from '@config/env'; import { typeormAdapter } from '@hedystia/better-auth-typeorm'; import { betterAuth } from 'better-auth'; import { bearer, openAPI } from 'better-auth/plugins'; import { DataSourceManager } from 'db/typeorm/database-connection'; import { UserRole } from '../../users/entities/user.entity'; const LOCAL_FRONTEND = 'http://localhost:3000'; export const BetterAuthConfig = betterAuth({ secret: env.ACCESS_TOKEN_SECRET, emailAndPassword: { enabled: true, autoSignIn: false }, socialProviders: { google: { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET, redirectURI: `${env.NEXT_PUBLIC_APP_BASE_URL}/api/auth/callback/google`, }, }, trustedOrigins: [env.NEXT_PUBLIC_APP_BASE_URL, LOCAL_FRONTEND], user: { modelName: 'users', additionalFields: { role: { type: 'string', enum: UserRole, default: UserRole.MEMBER, input: false }, }, }, session: { modelName: 'sessions' }, verification: { modelName: 'verifications' }, account: { modelName: 'accounts' }, advanced: { database: { generateId: false }, crossSubDomainCookies: { enabled: env.NODE_ENV === 'production', domain: env.NODE_ENV === 'production' ? '.meudominio.com' : undefined, }, cookiePrefix: 'ah', useSecureCookies: env.NODE_ENV === 'production', }, database: typeormAdapter(DataSourceManager), plugins: [bearer(), openAPI()], }); ``` Question: How can BetterAuth be configured so that the local front-end can authenticate with the production API and maintain the session, without affecting the production front-end? ### Current vs. Expected behavior Current Behavior: When logging in from the local front-end (http://localhost:3000) against the production API, the login appears to succeed, but no session is created or maintained. The user state does not update, and nothing happens on the front-end. Expected Behavior: The local front-end should successfully authenticate with the production API and maintain the session, just like the production front-end (app.meudominio.com) does. Note: Providing incomplete or missing information may result in the issue being closed. ### What version of Better Auth are you using? 1.3.7 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 25.0.0: Wed Sep 17 21:42:08 PDT 2025; root:xnu-12377.1.9~141/RELEASE_ARM64_T8132", "release": "25.0.0", "cpuCount": 10, "cpuModel": "Apple M4", "totalMemory": "16.00 GB", "freeMemory": "0.96 GB" }, "node": { "version": "v22.21.0", "env": "development" }, "packageManager": { "name": "npm", "version": "10.9.4" }, "frameworks": null, "databases": [ { "name": "pg", "version": "^8.16.3" } ], "betterAuth": { "version": "^1.3.7", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Backend ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, }); ``` ### Additional context _No response_
GiteaMirror added the bug label 2026-03-13 09:42:14 -05:00
Author
Owner

@better-auth-agent[bot] commented on GitHub (Nov 13, 2025):

It looks as if the issue is related to the cookie settings that are optimized for production (using secure, cross–subdomain cookies) and may not be compatible with the local front-end (which is running on http://localhost:3000). When your API is in production, secure cookies (and the cookie domain set to “.meudominio.com”) won’t be sent by the browser on a plain HTTP (or mismatched domain) request coming from localhost. You can try one of the following approaches:

• Temporarily disable setting secure cookies (that is, set useSecureCookies to false) when testing from localhost. This change allows the cookie to be set in your local environment without requiring HTTPS.
• Alternatively, consider using a different cookie configuration (for example, disabling crossSubDomainCookies) when the request is coming from your local front-end. You might want to detect the current origin and adjust these settings or maintain a separate configuration for local testing.
• Double-check that the local front-end’s origin (http://localhost:3000) is included in your trustedOrigins array, which you have already done.

These adjustments should allow the production API to send back session cookies that can be accepted by your local environment. Have you already tried modifying cookie settings for development, or would you like more details on setting up separate configurations for different environments?

Tag @better-auth-agent if you would like an answer from the Agent.

DiagramDiscordGitHub

Diagram Join Star

@better-auth-agent[bot] commented on GitHub (Nov 13, 2025): It looks as if the issue is related to the cookie settings that are optimized for production (using secure, cross–subdomain cookies) and may not be compatible with the local front-end (which is running on http://localhost:3000). When your API is in production, secure cookies (and the cookie domain set to “.meudominio.com”) won’t be sent by the browser on a plain HTTP (or mismatched domain) request coming from localhost. You can try one of the following approaches: • Temporarily disable setting secure cookies (that is, set useSecureCookies to false) when testing from localhost. This change allows the cookie to be set in your local environment without requiring HTTPS. • Alternatively, consider using a different cookie configuration (for example, disabling crossSubDomainCookies) when the request is coming from your local front-end. You might want to detect the current origin and adjust these settings or maintain a separate configuration for local testing. • Double-check that the local front-end’s origin (http://localhost:3000) is included in your trustedOrigins array, which you have already done. These adjustments should allow the production API to send back session cookies that can be accepted by your local environment. Have you already tried modifying cookie settings for development, or would you like more details on setting up separate configurations for different environments? Tag @better-auth-agent if you would like an answer from the Agent. <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) • [Discord](https://discord.gg/better-auth) • [GitHub](https://github.com/better-auth/better-auth) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/better-auth_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/better-auth) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/better-auth/better-auth)
Author
Owner

@dosubot[bot] commented on GitHub (Nov 13, 2025):

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

This is a browser limitation, not a BetterAuth bug: browsers do not allow cookies set for a production domain (like .meudominio.com) to be read or sent from localhost, and vice versa. This means session cookies set by your production API cannot be used by your local frontend, even if CORS and trustedOrigins are configured correctly. This is why your production frontend works, but your local frontend does not maintain a session with the production API [source].

There is no BetterAuth config that allows a single backend to set cookies for both localhost and a production domain at the same time. The recommended approach is to use environment variables to switch cookie domain and attributes depending on your environment: in production, set the domain to .meudominio.com; in development, either disable crossSubDomainCookies or set the domain to localhost if your backend is also local [source].

If you need to test your local frontend with the production API, consider these workarounds:

  • Use a local proxy or tunneling service (like ngrok) to expose your frontend on a custom domain that matches your production domain, so cookies can be shared [source].
  • Map a custom local domain (e.g., app.local and api.local) to 127.0.0.1 and update your hosts file, so both frontend and backend share a parent domain [source].
  • For true cross-origin (different root domains), session cookies must have SameSite=None and Secure, and must not have a Domain attribute; but even then, browsers will block cookies between localhost and a remote domain [source].

For local development, make sure your frontend HTTP client (e.g., axios or fetch) uses withCredentials: true or credentials: 'include', and that your backend CORS config allows credentials and echoes the exact origin [source].

If you need to test authentication flows locally against production, the only reliable way is to use a domain setup that matches your production environment, or use a proxy/tunnel as described above.

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 (Nov 13, 2025): <!-- Greeting --> Hi @viniimartins! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a browser limitation, not a BetterAuth bug: browsers do not allow cookies set for a production domain (like `.meudominio.com`) to be read or sent from `localhost`, and vice versa. This means session cookies set by your production API cannot be used by your local frontend, even if CORS and trustedOrigins are configured correctly. This is why your production frontend works, but your local frontend does not maintain a session with the production API [[source](https://github.com/better-auth/better-auth/issues/4100)]. There is no BetterAuth config that allows a single backend to set cookies for both `localhost` and a production domain at the same time. The recommended approach is to use environment variables to switch cookie domain and attributes depending on your environment: in production, set the domain to `.meudominio.com`; in development, either disable `crossSubDomainCookies` or set the domain to `localhost` if your backend is also local [[source](https://github.com/better-auth/better-auth/issues/3874)]. If you need to test your local frontend with the production API, consider these workarounds: - Use a local proxy or tunneling service (like ngrok) to expose your frontend on a custom domain that matches your production domain, so cookies can be shared [[source](https://github.com/better-auth/better-auth/discussions/5253)]. - Map a custom local domain (e.g., `app.local` and `api.local`) to `127.0.0.1` and update your hosts file, so both frontend and backend share a parent domain [[source](https://github.com/better-auth/better-auth/discussions/5253)]. - For true cross-origin (different root domains), session cookies must have `SameSite=None` and `Secure`, and must not have a `Domain` attribute; but even then, browsers will block cookies between `localhost` and a remote domain [[source](https://github.com/better-auth/better-auth/issues/4720)]. For local development, make sure your frontend HTTP client (e.g., axios or fetch) uses `withCredentials: true` or `credentials: 'include'`, and that your backend CORS config allows credentials and echoes the exact origin [[source](https://github.com/better-auth/better-auth/issues/5705)]. If you need to test authentication flows locally against production, the only reliable way is to use a domain setup that matches your production environment, or use a proxy/tunnel as described above. <!-- 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/4968c5b2-474d-4335-a465-824170b7b63b?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/4968c5b2-474d-4335-a465-824170b7b63b?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/4968c5b2-474d-4335-a465-824170b7b63b?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/4968c5b2-474d-4335-a465-824170b7b63b?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/4968c5b2-474d-4335-a465-824170b7b63b?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/4968c5b2-474d-4335-a465-824170b7b63b?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/4968c5b2-474d-4335-a465-824170b7b63b?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/5946)
Author
Owner

@JonasHiltl commented on GitHub (Nov 29, 2025):

I had the exact same issue but solved it by configuring custom cookie attributes.

advanced: {
  defaultCookieAttributes: {
    domain: isProd ? '.myapp.com' : 'localhost',
    sameSite: isProd ? 'none' : 'lax',
    secure: isProd ? true : undefined,
  },
},
@JonasHiltl commented on GitHub (Nov 29, 2025): I had the exact same issue but solved it by configuring custom cookie attributes. ```ts advanced: { defaultCookieAttributes: { domain: isProd ? '.myapp.com' : 'localhost', sameSite: isProd ? 'none' : 'lax', secure: isProd ? true : undefined, }, }, ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2297