[GH-ISSUE #6729] Better auth signin email logs in the wrong account #19235

Closed
opened 2026-04-15 18:05:07 -05:00 by GiteaMirror · 6 comments
Owner

Originally created by @rufique on GitHub (Dec 13, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6729

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

Better Auth Version: [run: npm list better-auth]
Node.js Version: 22.12.0
Package Manager: bun
Database: MySQL 8.4.3
Framework: Next.js 15 (App Router)
Deployment: Vercel, Localhost and Linux - Docker (Caprover)
Browser: Chrome/Firefox

// Session table (Drizzle schema)
export const session = mysqlTable("session", {
  id: varchar("id", { length: 255 }).primaryKey(),
  userId: varchar("userId", { length: 255 })
    .notNull()
    .references(() => user.id, { onDelete: "cascade" }),
  expiresAt: datetime("expiresAt").notNull(),
  token: varchar("token", { length: 255 }).notNull().unique(),
  ipAddress: varchar("ipAddress", { length: 255 }),
  userAgent: varchar("userAgent", { length: 255 }),
  createdAt: datetime("createdAt").notNull().default(sql`CURRENT_TIMESTAMP`),
  updatedAt: datetime("updatedAt")
    .notNull()
    .default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});

export const user = mysqlTable("user", {
  id: varchar("id", { length: 255 }).primaryKey(),
  name: varchar("name", { length: 255 }).notNull(),
  email: varchar("email", { length: 255 }).notNull().unique(),
  emailVerified: boolean("emailVerified").notNull().default(false),
  image: varchar("image", { length: 255 }),
  role: mysqlEnum("role", UserRoles).notNull().default("sales-agent"),
  createdAt: datetime("createdAt").notNull().default(sql`CURRENT_TIMESTAMP`),
  updatedAt: datetime("updatedAt")
    .notNull()
    .default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});

Current vs. Expected behavior

When logging in with user A's credentials, the session returned belongs to user B. This is a critical security vulnerability where users are authenticated as different users than the ones they logged in as.
Environment

What version of Better Auth are you using?

1.4.6

System info

{
  "system": {
    "platform": "win32",
    "arch": "x64",
    "version": "Windows 11 Pro",
    "release": "10.0.26090",
    "cpuCount": 4,
    "cpuModel": "Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz",
    "totalMemory": "7.88 GB",
    "freeMemory": "0.99 GB"
  },
  "node": {
    "version": "v22.12.0",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "10.9.0"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "15.5.9"
    },
    {
      "name": "react",
      "version": "19.1.0"
    }
  ],
  "databases": [
    {
      "name": "mysql2",
      "version": "^3.15.1"
    },
    {
      "name": "drizzle",
      "version": "^0.44.5"
    }
  ],
  "betterAuth": {
    "version": "^1.4.6",
    "config": {
      "emailAndPassword": {
        "enabled": true,
        "requireEmailVerification": false,
        "autoSignIn": false,
        "minPasswordLength": 6,
        "password": {}
      },
      "user": {
        "deleteUser": {
          "enabled": true
        },
        "additionalFields": {
          "role": {
            "type": "string",
            "defaultValue": "sales-agent",
            "required": true
          }
        }
      },
      "session": {
        "expiresIn": 604800,
        "updateAge": 86400,
        "freshAge": 3600
      },
      "secret": "[REDACTED]",
      "baseURL": "http://localhost:3000/api/v1/auth",
      "trustedOrigins": [
        "http://localhost:3000/api/v1/auth"
      ],
      "telemetry": {
        "debug": true
      },
      "plugins": [
        {
          "name": "next-cookies",
          "config": {
            "id": "next-cookies",
            "hooks": {
              "after": [
                {}
              ]
            }
          }
        },
        {
          "name": "admin",
          "config": {
            "id": "admin",
            "hooks": {
              "after": [
                {}
              ]
            },
            "endpoints": {},
            "$ERROR_CODES": {
              "FAILED_TO_CREATE_USER": "Failed to create user",
              "USER_ALREADY_EXISTS": "User already exists.",
              "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL": "User already exists. Use another email.",
              "YOU_CANNOT_BAN_YOURSELF": "You cannot ban yourself",
              "YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE": "You are not allowed to change users role",
              "YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS": "You are not allowed to create users",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS": "You are not allowed to list users",
              "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS": "You are not allowed to list users sessions",
              "YOU_ARE_NOT_ALLOWED_TO_BAN_USERS": "You are not allowed to ban users",
              "YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS": "You are not allowed to impersonate users",
              "YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS": "You are not allowed to revoke users sessions",
              "YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS": "You are not allowed to delete users",
              "YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD": "[REDACTED]",
              "BANNED_USER": "You have been banned from this application",
              "YOU_ARE_NOT_ALLOWED_TO_GET_USER": "You are not allowed to get user",
              "NO_DATA_TO_UPDATE": "No data to update",
              "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users",
              "YOU_CANNOT_REMOVE_YOURSELF": "You cannot remove yourself",
              "YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE": "You are not allowed to set a non-existent role value",
              "YOU_CANNOT_IMPERSONATE_ADMINS": "You cannot impersonate admins"
            },
            "schema": {
              "user": {
                "fields": {
                  "role": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "banned": {
                    "type": "boolean",
                    "defaultValue": false,
                    "required": false,
                    "input": false
                  },
                  "banReason": {
                    "type": "string",
                    "required": false,
                    "input": false
                  },
                  "banExpires": {
                    "type": "date",
                    "required": false,
                    "input": false
                  }
                }
              },
              "session": {
                "fields": {
                  "impersonatedBy": {
                    "type": "string",
                    "required": false
                  }
                }
              }
            },
            "options": {
              "adminRoles": [
                "admin",
                "manager"
              ],
              "defaultRole": "sales-agent",
              "roles": {
                "admin": {
                  "statements": {
                    "user": [
                      "create",
                      "list",
                      "set-role",
                      "ban",
                      "impersonate",
                      "delete",
                      "set-password",
                      "get",
                      "update"
                    ],
                    "session": [
                      "list",
                      "revoke",
                      "delete"
                    ]
                  }
                },
                "sales-agent": {
                  "statements": {
                    "session": [],
                    "user": []
                  }
                },
                "sales-manager": {
                  "statements": {
                    "session": [],
                    "user": []
                  }
                },
                "manager": {
                  "statements": {
                    "session": [],
                    "user": []
                  }
                }
              }
            }
          }
        },
        {
          "name": "custom-session",
          "config": {
            "id": "custom-session",
            "hooks": {
              "after": [
                {}
              ]
            },
            "endpoints": {},
            "$Infer": {
              "Session": {}
            }
          }
        }
      ],
      "advanced": {
        "database": {
          "generateId": false
        },
        "cookiePrefix": "_digilearn-crm",
        "crossSubDomainCookies": {
          "enabled": false
        }
      }
    }
  }
}

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

Backend, Client

Auth config (if applicable)

// auth.ts (sanitized)
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { nextCookies } from "better-auth/next-js";
import { admin, customSession } from "better-auth/plugins";

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: "mysql",
    schema: {
      user: schema.user,
      session: schema.session,
      account: schema.account,
      verification: schema.verification,
    },
  }),
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: false,
    autoSignIn: false,
    minPasswordLength: 6,
  },
  user: {
    deleteUser: {
      enabled: true,
    },
    additionalFields: {
      role: {
        type: "string",
        defaultValue: "sales-agent",
        required: true,
      },
    },
  },
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days
    updateAge: 60 * 60 * 24,
    freshAge: 60 * 60,
  },
  secret: process.env.BETTER_AUTH_SECRET!,
  baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL || "http://localhost:3000/api/v1/auth",
  trustedOrigins: [
    process.env.NEXT_PUBLIC_BETTER_AUTH_URL || "http://localhost:3000/api/v1/auth",
  ],
  plugins: [
    nextCookies(),
    admin({
      adminRoles: ["admin", "manager"],
      defaultRole: "sales-agent",
    }),
    customSession(async ({ user, session }) => {
      if (!user || !session) {
        return {};
      }

      const dbPermissions = await db.query.permissions.findMany({
        where: eq(schema.permissions.role, user.role),
      });

      return {
        session,
        user,
        userPermissions: dbPermissions,
      };
    }),
  ],
  advanced: {
    database: {
      generateId: false,
    },
    cookiePrefix: "custom-prefix",
    crossSubDomainCookies: {
      enabled: false,
    },
  },
});


import { createAuthClient } from "better-auth/react";
import { adminClient, customSessionClient } from "better-auth/client/plugins";
import { auth, CustomSession } from "./auth";

export const authClient = createAuthClient({
  baseURL:
    process.env.NEXT_PUBLIC_BETTER_AUTH_URL ||
    "http://localhost:3000/api/v1/auth",
  fetchOptions: {
    credentials: "include", // Important for cookies
  },
  plugins: [adminClient(), customSessionClient<typeof auth>()],
});

export const { signIn, signUp, getSession, signOut } = authClient;

export const useSession = () =>
  authClient.useSession() as { data: CustomSession };

Additional context

customSession(async ({ user, session }) => {
console.log('CustomSession called:', {
userId: user?.id,
userEmail: user?.email,
sessionId: session?.id,
sessionUserId: session?.userId
});
// ... rest of code
})


**Output when logging in with `busid@clearhue.co.zw`:**

CustomSession called: {
userId: '88370325-ec95-4c86-979d-a05b8dfbbae6',
userEmail: 'doobsie@clearhue.online', // WRONG USER
sessionId: '85e6af57-2c75-494b-b1c8-65bd645ac910',
sessionUserId: '88370325-ec95-4c86-979d-a05b8dfbbae6'
}
Returning session for: doobsie@clearhue.online with 6 permissions

Originally created by @rufique on GitHub (Dec 13, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6729 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce Better Auth Version: [run: npm list better-auth] Node.js Version: 22.12.0 Package Manager: bun Database: MySQL 8.4.3 Framework: Next.js 15 (App Router) Deployment: Vercel, Localhost and Linux - Docker (Caprover) Browser: Chrome/Firefox ``` // Session table (Drizzle schema) export const session = mysqlTable("session", { id: varchar("id", { length: 255 }).primaryKey(), userId: varchar("userId", { length: 255 }) .notNull() .references(() => user.id, { onDelete: "cascade" }), expiresAt: datetime("expiresAt").notNull(), token: varchar("token", { length: 255 }).notNull().unique(), ipAddress: varchar("ipAddress", { length: 255 }), userAgent: varchar("userAgent", { length: 255 }), createdAt: datetime("createdAt").notNull().default(sql`CURRENT_TIMESTAMP`), updatedAt: datetime("updatedAt") .notNull() .default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`), }); export const user = mysqlTable("user", { id: varchar("id", { length: 255 }).primaryKey(), name: varchar("name", { length: 255 }).notNull(), email: varchar("email", { length: 255 }).notNull().unique(), emailVerified: boolean("emailVerified").notNull().default(false), image: varchar("image", { length: 255 }), role: mysqlEnum("role", UserRoles).notNull().default("sales-agent"), createdAt: datetime("createdAt").notNull().default(sql`CURRENT_TIMESTAMP`), updatedAt: datetime("updatedAt") .notNull() .default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`), }); ``` ### Current vs. Expected behavior When logging in with user A's credentials, the session returned belongs to user B. This is a critical security vulnerability where users are authenticated as different users than the ones they logged in as. Environment ### What version of Better Auth are you using? 1.4.6 ### System info ```bash { "system": { "platform": "win32", "arch": "x64", "version": "Windows 11 Pro", "release": "10.0.26090", "cpuCount": 4, "cpuModel": "Intel(R) Core(TM) i5-6300U CPU @ 2.40GHz", "totalMemory": "7.88 GB", "freeMemory": "0.99 GB" }, "node": { "version": "v22.12.0", "env": "development" }, "packageManager": { "name": "npm", "version": "10.9.0" }, "frameworks": [ { "name": "next", "version": "15.5.9" }, { "name": "react", "version": "19.1.0" } ], "databases": [ { "name": "mysql2", "version": "^3.15.1" }, { "name": "drizzle", "version": "^0.44.5" } ], "betterAuth": { "version": "^1.4.6", "config": { "emailAndPassword": { "enabled": true, "requireEmailVerification": false, "autoSignIn": false, "minPasswordLength": 6, "password": {} }, "user": { "deleteUser": { "enabled": true }, "additionalFields": { "role": { "type": "string", "defaultValue": "sales-agent", "required": true } } }, "session": { "expiresIn": 604800, "updateAge": 86400, "freshAge": 3600 }, "secret": "[REDACTED]", "baseURL": "http://localhost:3000/api/v1/auth", "trustedOrigins": [ "http://localhost:3000/api/v1/auth" ], "telemetry": { "debug": true }, "plugins": [ { "name": "next-cookies", "config": { "id": "next-cookies", "hooks": { "after": [ {} ] } } }, { "name": "admin", "config": { "id": "admin", "hooks": { "after": [ {} ] }, "endpoints": {}, "$ERROR_CODES": { "FAILED_TO_CREATE_USER": "Failed to create user", "USER_ALREADY_EXISTS": "User already exists.", "USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL": "User already exists. Use another email.", "YOU_CANNOT_BAN_YOURSELF": "You cannot ban yourself", "YOU_ARE_NOT_ALLOWED_TO_CHANGE_USERS_ROLE": "You are not allowed to change users role", "YOU_ARE_NOT_ALLOWED_TO_CREATE_USERS": "You are not allowed to create users", "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS": "You are not allowed to list users", "YOU_ARE_NOT_ALLOWED_TO_LIST_USERS_SESSIONS": "You are not allowed to list users sessions", "YOU_ARE_NOT_ALLOWED_TO_BAN_USERS": "You are not allowed to ban users", "YOU_ARE_NOT_ALLOWED_TO_IMPERSONATE_USERS": "You are not allowed to impersonate users", "YOU_ARE_NOT_ALLOWED_TO_REVOKE_USERS_SESSIONS": "You are not allowed to revoke users sessions", "YOU_ARE_NOT_ALLOWED_TO_DELETE_USERS": "You are not allowed to delete users", "YOU_ARE_NOT_ALLOWED_TO_SET_USERS_PASSWORD": "[REDACTED]", "BANNED_USER": "You have been banned from this application", "YOU_ARE_NOT_ALLOWED_TO_GET_USER": "You are not allowed to get user", "NO_DATA_TO_UPDATE": "No data to update", "YOU_ARE_NOT_ALLOWED_TO_UPDATE_USERS": "You are not allowed to update users", "YOU_CANNOT_REMOVE_YOURSELF": "You cannot remove yourself", "YOU_ARE_NOT_ALLOWED_TO_SET_NON_EXISTENT_VALUE": "You are not allowed to set a non-existent role value", "YOU_CANNOT_IMPERSONATE_ADMINS": "You cannot impersonate admins" }, "schema": { "user": { "fields": { "role": { "type": "string", "required": false, "input": false }, "banned": { "type": "boolean", "defaultValue": false, "required": false, "input": false }, "banReason": { "type": "string", "required": false, "input": false }, "banExpires": { "type": "date", "required": false, "input": false } } }, "session": { "fields": { "impersonatedBy": { "type": "string", "required": false } } } }, "options": { "adminRoles": [ "admin", "manager" ], "defaultRole": "sales-agent", "roles": { "admin": { "statements": { "user": [ "create", "list", "set-role", "ban", "impersonate", "delete", "set-password", "get", "update" ], "session": [ "list", "revoke", "delete" ] } }, "sales-agent": { "statements": { "session": [], "user": [] } }, "sales-manager": { "statements": { "session": [], "user": [] } }, "manager": { "statements": { "session": [], "user": [] } } } } } }, { "name": "custom-session", "config": { "id": "custom-session", "hooks": { "after": [ {} ] }, "endpoints": {}, "$Infer": { "Session": {} } } } ], "advanced": { "database": { "generateId": false }, "cookiePrefix": "_digilearn-crm", "crossSubDomainCookies": { "enabled": false } } } } } ``` ### Which area(s) are affected? (Select all that apply) Backend, Client ### Auth config (if applicable) ```typescript // auth.ts (sanitized) import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { nextCookies } from "better-auth/next-js"; import { admin, customSession } from "better-auth/plugins"; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "mysql", schema: { user: schema.user, session: schema.session, account: schema.account, verification: schema.verification, }, }), emailAndPassword: { enabled: true, requireEmailVerification: false, autoSignIn: false, minPasswordLength: 6, }, user: { deleteUser: { enabled: true, }, additionalFields: { role: { type: "string", defaultValue: "sales-agent", required: true, }, }, }, session: { expiresIn: 60 * 60 * 24 * 7, // 7 days updateAge: 60 * 60 * 24, freshAge: 60 * 60, }, secret: process.env.BETTER_AUTH_SECRET!, baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL || "http://localhost:3000/api/v1/auth", trustedOrigins: [ process.env.NEXT_PUBLIC_BETTER_AUTH_URL || "http://localhost:3000/api/v1/auth", ], plugins: [ nextCookies(), admin({ adminRoles: ["admin", "manager"], defaultRole: "sales-agent", }), customSession(async ({ user, session }) => { if (!user || !session) { return {}; } const dbPermissions = await db.query.permissions.findMany({ where: eq(schema.permissions.role, user.role), }); return { session, user, userPermissions: dbPermissions, }; }), ], advanced: { database: { generateId: false, }, cookiePrefix: "custom-prefix", crossSubDomainCookies: { enabled: false, }, }, }); import { createAuthClient } from "better-auth/react"; import { adminClient, customSessionClient } from "better-auth/client/plugins"; import { auth, CustomSession } from "./auth"; export const authClient = createAuthClient({ baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL || "http://localhost:3000/api/v1/auth", fetchOptions: { credentials: "include", // Important for cookies }, plugins: [adminClient(), customSessionClient<typeof auth>()], }); export const { signIn, signUp, getSession, signOut } = authClient; export const useSession = () => authClient.useSession() as { data: CustomSession }; ``` ### Additional context customSession(async ({ user, session }) => { console.log('CustomSession called:', { userId: user?.id, userEmail: user?.email, sessionId: session?.id, sessionUserId: session?.userId }); // ... rest of code }) ``` **Output when logging in with `busid@clearhue.co.zw`:** ``` CustomSession called: { userId: '88370325-ec95-4c86-979d-a05b8dfbbae6', userEmail: 'doobsie@clearhue.online', // ❌ WRONG USER sessionId: '85e6af57-2c75-494b-b1c8-65bd645ac910', sessionUserId: '88370325-ec95-4c86-979d-a05b8dfbbae6' } Returning session for: doobsie@clearhue.online with 6 permissions
GiteaMirror added the lockedbug labels 2026-04-15 18:05:07 -05:00
Author
Owner

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

This issue is almost always caused by stale or mismatched session cookies or cache, not a bug in the core session-user association logic. Here’s what’s happening and how to fix it:

  • Better Auth caches session and user data in a session_data cookie (and optionally in secondary storage). If this cookie isn’t cleared or updated after sign-in/sign-out, you can get a session for the wrong user—even if the sessionId and userId match, the user object may be stale or from a previous login. This is especially common if you’re using custom endpoints, middleware, or proxies that don’t forward the Set-Cookie header from Better Auth responses to the client, or if you’re not using asResponse: true when calling Better Auth API methods in custom handlers [example & fix].

  • Always ensure that after sign-in or sign-out, all session cookies (including chunked cookies if your session data is large) are cleared. If you use custom API routes or middleware, make sure you forward all Set-Cookie headers from Better Auth to the client. If you don’t, the client will keep using the old session cache and you’ll see exactly this kind of user/session mismatch.

  • To force a session refresh and avoid stale cache, call getSession({ disableCookieCache: true }) after sign-in. This fetches the session from the database and updates the cookie [docs].

  • If you’re manually setting cookies or using a non-standard client, always use authClient.getCookie() to get the properly signed and encoded cookie string. Sending a raw token or an incorrectly formatted cookie will break session validation and can cause the wrong user to be returned [example].

  • If you use secondary storage, make sure it’s being cleared and updated on sign-in/sign-out. Stale entries there can also cause mismatches.

Debug checklist:

  1. Sign out, clear all cookies (including chunked session_data cookies), and sign in as a different user. Check if the session matches the correct user.
  2. If you use custom endpoints, always return the Better Auth API response with asResponse: true and forward all Set-Cookie headers.
  3. After sign-in, call getSession({ disableCookieCache: true }) to force a fresh session.
  4. If you still see mismatches, check your secondary storage and logs for stale session data.

Recent Better Auth versions include fixes to always preserve user.id in the cookie cache and improve session freshness checks [PR #6452, PR #6031]. Make sure you’re on the latest version.

Let me know if you want a code snippet for cookie invalidation or forwarding headers in your custom endpoints.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:3649392062 --> @dosubot[bot] commented on GitHub (Dec 13, 2025): <!-- Answer --> This issue is almost always caused by stale or mismatched session cookies or cache, not a bug in the core session-user association logic. Here’s what’s happening and how to fix it: - Better Auth caches session and user data in a `session_data` cookie (and optionally in secondary storage). If this cookie isn’t cleared or updated after sign-in/sign-out, you can get a session for the wrong user—even if the sessionId and userId match, the user object may be stale or from a previous login. This is especially common if you’re using custom endpoints, middleware, or proxies that don’t forward the `Set-Cookie` header from Better Auth responses to the client, or if you’re not using `asResponse: true` when calling Better Auth API methods in custom handlers [[example & fix](https://github.com/better-auth/better-auth/issues/6530)]. - Always ensure that after sign-in or sign-out, all session cookies (including chunked cookies if your session data is large) are cleared. If you use custom API routes or middleware, make sure you forward all `Set-Cookie` headers from Better Auth to the client. If you don’t, the client will keep using the old session cache and you’ll see exactly this kind of user/session mismatch. - To force a session refresh and avoid stale cache, call `getSession({ disableCookieCache: true })` after sign-in. This fetches the session from the database and updates the cookie [[docs](https://github.com/better-auth/better-auth/discussions/4231)]. - If you’re manually setting cookies or using a non-standard client, always use `authClient.getCookie()` to get the properly signed and encoded cookie string. Sending a raw token or an incorrectly formatted cookie will break session validation and can cause the wrong user to be returned [[example](https://github.com/better-auth/better-auth/issues/3892#issuecomment-3170390281)]. - If you use secondary storage, make sure it’s being cleared and updated on sign-in/sign-out. Stale entries there can also cause mismatches. **Debug checklist:** 1. Sign out, clear all cookies (including chunked session_data cookies), and sign in as a different user. Check if the session matches the correct user. 2. If you use custom endpoints, always return the Better Auth API response with `asResponse: true` and forward all `Set-Cookie` headers. 3. After sign-in, call `getSession({ disableCookieCache: true })` to force a fresh session. 4. If you still see mismatches, check your secondary storage and logs for stale session data. Recent Better Auth versions include fixes to always preserve `user.id` in the cookie cache and improve session freshness checks [[PR #6452](https://github.com/better-auth/better-auth/pull/6452), [PR #6031](https://github.com/better-auth/better-auth/pull/6031)]. Make sure you’re on the latest version. Let me know if you want a code snippet for cookie invalidation or forwarding headers in your custom endpoints. <!-- 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/991f401a-1168-417d-b0fa-734ac5f0b622?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/991f401a-1168-417d-b0fa-734ac5f0b622?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/991f401a-1168-417d-b0fa-734ac5f0b622?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/991f401a-1168-417d-b0fa-734ac5f0b622?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/991f401a-1168-417d-b0fa-734ac5f0b622?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/991f401a-1168-417d-b0fa-734ac5f0b622?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/991f401a-1168-417d-b0fa-734ac5f0b622?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20issue%20is%20almost%20always%20caused%20by%20stale%20or%20mismatched%20session%20cookies%20or%20cache%2C%20not%20a%20bug%20in%20the%20core%20session-user%20association%20logic.%20Here%E2%80%99s%20what%E2%80%99s%20happening%20and%20how%20to%20fix%20it%3A%0A%0A-%20Better%20Auth%20caches%20session%20and%20user%20data%20in%20a%20%60session_data%60%20cookie%20%28and%20optionally%20in%20secondary%20storage%29.%20If%20this%20cookie%20isn%E2%80%99t%20cleared%20or%20updated%20after%20sign-in/sign-out%2C%20you%20can%20get%20a%20session%20for%20the%20wrong%20user%E2%80%94even%20if%20the%20sessionId%20and%20userId%20match%2C%20the%20user%20object%20may%20be%20stale%20or%20from%20a%20previous%20login.%20This%20is%20especially%20common%20if%20you%E2%80%99re%20using%20custom%20endpoints%2C%20middleware%2C%20or%20proxies%20that%20don%E2%80%99t%20forward%20the%20%60Set-Cookie%60%20header%20from%20Better%20Auth%20responses%20to%20the%20client%2C%20or%20if%20you%E2%80%99re%20not%20using%20%60asResponse%3A%20true%60%20when%20calling%20Better%20Auth%20API%20methods%20in%20custom%20handlers%20%5B%5Bexample%20%26%20fix%5D%28https%3A//github.com/better-auth/better-auth/issues/6530%29%5D.%0A%0A-%20Always%20ensure%20that%20after%20sign-in%20or%20sign-out%2C%20all%20session%20cookies%20%28including%20chunked%20cookies%20if%20your%20session%20data%20is%20large%29%20are%20cleared.%20If%20you%20use%20custom%20API%20routes%20or%20middleware%2C%20make%20sure%20you%20forward%20all%20%60Set-Cookie%60%20headers%20from%20Better%20Auth%20to%20the%20client.%20If%20you%20don%E2%80%99t%2C%20the%20client%20will%20keep%20using%20the%20old%20session%20cache%20and%20you%E2%80%99ll%20see%20exactly%20this%20kind%20of%20user/session%20mismatch.%0A%0A-%20To%20force%20a%20session%20refresh%20and%20avoid%20stale%20cache%2C%20call%20%60getSession%28%7B%20disableCookieCache%3A%20true%20%7D%29%60%20after%20sign-in.%20This%20fetches%20the%20session%20from%20the%20database%20and%20updates%20the%20cookie%20%5B%5Bdocs%5D%28https%3A//github.com/better-auth/better-auth/discussions/4231%29%5D.%0A%0A-%20If%20you%E2%80%99re%20manually%20setting%20cookies%20or%20using%20a%20non-standard%20client%2C%20always%20use%20%60authClient.getCookie%28%29%60%20to%20get%20the%20properly%20signed%20and%20encoded%20cookie%20string.%20Sending%20a%20raw%20token%20or%20an%20incorrectly%20formatted%20cookie%20will%20break%20session%20validation%20and%20can%20cause%20the%20wrong%20user%20to%20be%20returned%20%5B%5Bexample%5D%28https%3A//github.com/better-auth/better-auth/issues/3892%23issuecomment-3170390281%29%5D.%0A%0A-%20If%20you%20use%20secondary%20storage%2C%20make%20sure%20it%E2%80%99s%20being%20cleared%20and%20updated%20on%20sign-in/sign-out.%20Stale%20entries%20there%20can%20also%20cause%20mismatches.%0A%0A%2A%2ADebug%20checklist%3A%2A%2A%0A1.%20Sign%20out%2C%20clear%20all%20cookies%20%28including%20chunked%20session_data%20cookies%29%2C%20and%20sign%20in%20as%20a%20different%20user.%20Check%20if%20the%20session%20matches%20the%20correct%20user.%0A2.%20If%20you%20use%20custom%20endpoints%2C%20always%20return%20the%20Better%20Auth%20API%20response%20with%20%60asResponse%3A%20true%60%20and%20forward%20all%20%60Set-Cookie%60%20headers.%0A3.%20After%20sign-in%2C%20call%20%60getSession%28%7B%20disableCookieCache%3A%20true%20%7D%29%60%20to%20force%20a%20fresh%20session.%0A4.%20If%20you%20still%20see%20mismatches%2C%20check%20your%20secondary%20storage%20and%20logs%20for%20stale%20session%20data.%0A%0ARecent%20Better%20Auth%20versions%20include%20fixes%20to%20always%20preserve%20%60user.id%60%20in%20the%20cookie%20cache%20and%20improve%20session%20freshness%20checks%20%5B%5BPR%20%236452%5D%28https%3A//github.com/better-auth/better-auth/pull/6452%29%2C%20%5BPR%20%236031%5D%28https%3A//github.com/better-auth/better-auth/pull/6031%29%5D.%20Make%20sure%20you%E2%80%99re%20on%20the%20latest%20version.%0A%0ALet%20me%20know%20if%20you%20want%20a%20code%20snippet%20for%20cookie%20invalidation%20or%20forwarding%20headers%20in%20your%20custom%20endpoints.)&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/6729)
Author
Owner

@rufique commented on GitHub (Dec 13, 2025):

@dosu.

Well, there's also the issue of when a user signs in on a browser they have never used before, but gets the wrong session. Using similar settings

<!-- gh-comment-id:3649404524 --> @rufique commented on GitHub (Dec 13, 2025): @dosu. Well, there's also the issue of when a user signs in on a browser they have never used before, but gets the wrong session. Using similar settings
Author
Owner

@rufique commented on GitHub (Dec 15, 2025):

@dosu

I have added a session refresh component

"use client";
import { useEffect } from "react";
import { authClient } from "~/lib/auth-client";

export function SessionRefresher() {
  const { refetch } = authClient.useSession()
  useEffect(() => {
    const onFocus = () => refetch({
      query: {
        disableCookieCache: true
      }
    })
    window.addEventListener('focus', onFocus)
    return () => window.removeEventListener('focus', onFocus)
  }, [refetch])
  return null
}

and disabledCookieCache, I have also added session refresh after a successful login and logout, then used a different laptop without any sessions, and when I log in with user A, I get user B., meaning it's not caching the session, rather an account mismatch. Could there be a bug with the better auth core module?

<!-- gh-comment-id:3654374846 --> @rufique commented on GitHub (Dec 15, 2025): @dosu I have added a session refresh component ``` "use client"; import { useEffect } from "react"; import { authClient } from "~/lib/auth-client"; export function SessionRefresher() { const { refetch } = authClient.useSession() useEffect(() => { const onFocus = () => refetch({ query: { disableCookieCache: true } }) window.addEventListener('focus', onFocus) return () => window.removeEventListener('focus', onFocus) }, [refetch]) return null } ``` and disabledCookieCache, I have also added session refresh after a successful login and logout, then used a different laptop without any sessions, and when I log in with user A, I get user B., meaning it's not caching the session, rather an account mismatch. Could there be a bug with the better auth core module?
Author
Owner

@Bekacru commented on GitHub (Dec 16, 2025):

is this only happening when you enable custom session?

<!-- gh-comment-id:3662614407 --> @Bekacru commented on GitHub (Dec 16, 2025): is this only happening when you enable custom session?
Author
Owner

@dosubot[bot] commented on GitHub (Mar 17, 2026):

Hi, @rufique. I'm Dosu, and I'm helping the better-auth team manage their backlog and am marking this issue as stale.

Issue Summary:

  • You reported a critical security issue in Better Auth v1.4.6 where logging in with one user's credentials returns a session for a different user, even on a fresh browser.
  • Initial advice was to clear session cookies, forward Set-Cookie headers properly, and use getSession({ disableCookieCache: true }) to force session refresh.
  • Despite implementing these fixes and adding a session refresh component, you still experience user/session mismatches.
  • This raised concerns about a possible bug in the core module.
  • Another user inquired if the issue occurs only when custom sessions are enabled.

Next Steps:

  • Please confirm if this issue is still relevant with the latest version of better-auth and if the problem persists.
  • If it is still an issue, you can keep the discussion open by commenting here; otherwise, I will automatically close this issue in 7 days.

Thank you for your understanding and contribution!

<!-- gh-comment-id:4076144502 --> @dosubot[bot] commented on GitHub (Mar 17, 2026): Hi, @rufique. I'm [Dosu](https://dosu.dev), and I'm helping the better-auth team manage their backlog and am marking this issue as stale. **Issue Summary:** - You reported a critical security issue in Better Auth v1.4.6 where logging in with one user's credentials returns a session for a different user, even on a fresh browser. - Initial advice was to clear session cookies, forward Set-Cookie headers properly, and use `getSession({ disableCookieCache: true })` to force session refresh. - Despite implementing these fixes and adding a session refresh component, you still experience user/session mismatches. - This raised concerns about a possible bug in the core module. - Another user inquired if the issue occurs only when custom sessions are enabled. **Next Steps:** - Please confirm if this issue is still relevant with the latest version of better-auth and if the problem persists. - If it is still an issue, you can keep the discussion open by commenting here; otherwise, I will automatically close this issue in 7 days. Thank you for your understanding and contribution!
Author
Owner

@github-actions[bot] commented on GitHub (Mar 31, 2026):

This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.

<!-- gh-comment-id:4165908241 --> @github-actions[bot] commented on GitHub (Mar 31, 2026): This issue has been locked as it was closed more than 7 days ago. If you're experiencing a similar problem or you have additional context, please open a new issue and reference this one.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#19235