[GH-ISSUE #6567] Can not signOut after Impersonate #10556

Closed
opened 2026-04-13 06:46:47 -05:00 by GiteaMirror · 3 comments
Owner

Originally created by @Calyrex on GitHub (Dec 6, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/6567

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Create an admin user
  2. use Admin plugin
  3. Impersonate a user: authClient.admin.impersonateUser();
  4. Stop Impersonate a user: authClient.admin.stopImpersonating();
  5. signOut: authClient.signOut()
  6. Can not sign out, error: 307

Current vs. Expected behavior

Expected behavior
When stopping admin impersonation and sign out, the admin_session cookie is not cleared.
This leaves the system in an inconsistent authentication state and can cause logout failures and redirect loops 307

signOut: Error 400 - FAILED_TO_GET_SESSION

What version of Better Auth are you using?

1.4.3

System info

{
  "system": {
    "platform": "darwin",
    "arch": "arm64",
    "version": "Darwin Kernel Version 25.1.0: Mon Oct 20 19:34:03 PDT 2025; root:xnu-12377.41.6~2/RELEASE_ARM64_T8112",
    "release": "25.1.0",
    "cpuCount": 8,
    "cpuModel": "Apple M2",
    "totalMemory": "8.00 GB",
    "freeMemory": "0.11 GB"
  },
  "node": {
    "version": "v25.2.1",
    "env": "development"
  },
  "packageManager": {
    "name": "npm",
    "version": "11.6.2"
  },
  "frameworks": [
    {
      "name": "next",
      "version": "16.0.7"
    },
    {
      "name": "react",
      "version": "19.2.1"
    }
  ],
  "databases": [
    {
      "name": "@prisma/client",
      "version": "^6.19.0"
    }
  ],
  "betterAuth": {
    "version": "^1.4.3",
    "config": {
      "emailAndPassword": {
        "enabled": true
      },
      "socialProviders": {
        "google": {
          "clientId": "[REDACTED]",
          "clientSecret": "[REDACTED]",
          "redirectURI": "http://localhost:3000/api/auth/callback/google",
          "accessType": "offline",
          "prompt": "select_account consent"
          "prompt": "select_account consent"
        }
      },
      "baseURL": "http://localhost:3000",
      "trustedOrigins": [
        "http://localhost:3000",
        "http://localhost:3001"
      ],
      "advanced": {
        "useSecureCookies": false,
        "cookiePrefix": "better-auth"
      },
      "plugins": [
        {
          "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"
            },
            "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": {
              "defaultRole": "user",
              "adminRoles": [
                "admin"
              ],
              "impersonationSessionDuration": 3600
            }
          }
        },
        {
          "name": "next-cookies",
          "config": {
            "id": "next-cookies",
            "hooks": {
              "after": [
                {}
              ]
            }
          }
        }
      ],
      "session": {
        "expiresIn": 604800,
        "updateAge": 86400
      }
    }
  }
}

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

Client

Auth config (if applicable)

import { betterAuth } from "better-auth";
import { admin } from "better-auth/plugins";
import { nextCookies } from "better-auth/next-js";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { prisma } from "./prisma";

export const auth = betterAuth({
  database: prismaAdapter(prisma, {
    provider: "postgresql",
  }),
  emailAndPassword: {
    enabled: true,
  },
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
      redirectURI: `${process.env.BETTER_AUTH_URL}/api/auth/callback/google`,
      accessType: "offline",
      prompt: "select_account consent",
    },
  },
  baseURL: process.env.BETTER_AUTH_URL!,
  trustedOrigins: [
    process.env.BETTER_AUTH_URL!,
    process.env.NEXT_PUBLIC_APP_URL!,
  ],
  advanced: {
    useSecureCookies: process.env.NODE_ENV === "production",
    cookiePrefix: "better-auth",
  },
  plugins: [
    admin({
      defaultRole: "user",
      adminRoles: ["admin"],
      impersonationSessionDuration: 60 * 60,
    }),
    nextCookies(),
  ],
  session: {
    expiresIn: 60 * 60 * 24 * 7,
    updateAge: 60 * 60 * 24,
  },
});

export type Session = typeof auth.$Infer.Session;

Additional context

No response

Originally created by @Calyrex on GitHub (Dec 6, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/6567 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Create an admin user 2. use Admin plugin 3. Impersonate a user: authClient.admin.impersonateUser(); 4. Stop Impersonate a user: authClient.admin.stopImpersonating(); 5. signOut: authClient.signOut() 6. Can not sign out, error: 307 ### Current vs. Expected behavior Expected behavior When stopping admin impersonation and sign out, the **admin_session** cookie is not cleared. This leaves the system in an inconsistent authentication state and can cause logout failures and redirect loops 307 signOut: Error 400 - FAILED_TO_GET_SESSION ### What version of Better Auth are you using? 1.4.3 ### System info ```bash { "system": { "platform": "darwin", "arch": "arm64", "version": "Darwin Kernel Version 25.1.0: Mon Oct 20 19:34:03 PDT 2025; root:xnu-12377.41.6~2/RELEASE_ARM64_T8112", "release": "25.1.0", "cpuCount": 8, "cpuModel": "Apple M2", "totalMemory": "8.00 GB", "freeMemory": "0.11 GB" }, "node": { "version": "v25.2.1", "env": "development" }, "packageManager": { "name": "npm", "version": "11.6.2" }, "frameworks": [ { "name": "next", "version": "16.0.7" }, { "name": "react", "version": "19.2.1" } ], "databases": [ { "name": "@prisma/client", "version": "^6.19.0" } ], "betterAuth": { "version": "^1.4.3", "config": { "emailAndPassword": { "enabled": true }, "socialProviders": { "google": { "clientId": "[REDACTED]", "clientSecret": "[REDACTED]", "redirectURI": "http://localhost:3000/api/auth/callback/google", "accessType": "offline", "prompt": "select_account consent" "prompt": "select_account consent" } }, "baseURL": "http://localhost:3000", "trustedOrigins": [ "http://localhost:3000", "http://localhost:3001" ], "advanced": { "useSecureCookies": false, "cookiePrefix": "better-auth" }, "plugins": [ { "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" }, "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": { "defaultRole": "user", "adminRoles": [ "admin" ], "impersonationSessionDuration": 3600 } } }, { "name": "next-cookies", "config": { "id": "next-cookies", "hooks": { "after": [ {} ] } } } ], "session": { "expiresIn": 604800, "updateAge": 86400 } } } } ``` ### Which area(s) are affected? (Select all that apply) Client ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth"; import { admin } from "better-auth/plugins"; import { nextCookies } from "better-auth/next-js"; import { prismaAdapter } from "better-auth/adapters/prisma"; import { prisma } from "./prisma"; export const auth = betterAuth({ database: prismaAdapter(prisma, { provider: "postgresql", }), emailAndPassword: { enabled: true, }, socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, redirectURI: `${process.env.BETTER_AUTH_URL}/api/auth/callback/google`, accessType: "offline", prompt: "select_account consent", }, }, baseURL: process.env.BETTER_AUTH_URL!, trustedOrigins: [ process.env.BETTER_AUTH_URL!, process.env.NEXT_PUBLIC_APP_URL!, ], advanced: { useSecureCookies: process.env.NODE_ENV === "production", cookiePrefix: "better-auth", }, plugins: [ admin({ defaultRole: "user", adminRoles: ["admin"], impersonationSessionDuration: 60 * 60, }), nextCookies(), ], session: { expiresIn: 60 * 60 * 24 * 7, updateAge: 60 * 60 * 24, }, }); export type Session = typeof auth.$Infer.Session; ``` ### Additional context _No response_
GiteaMirror added the lockedbug labels 2026-04-13 06:46:47 -05:00
Author
Owner

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

Hi there! It looks like the signOut issue after stopping impersonation is occurring because the admin session isn’t being completely cleared. This can leave a lingering admin_session cookie that interferes with the normal signOut process, resulting in a 307 redirect and a 400 error when attempting to get the session.

A few troubleshooting steps you could try are:
• Verify that you’re calling stopImpersonating before signOut, ensuring the session is fully terminated.
• As a temporary workaround, try manually clearing the admin_session cookie after stopping impersonation.
• Double-check your cookie configuration and prefix settings to ensure they’re applied consistently to both regular and admin sessions.

These steps align with similar reported issues where improperly cleared admin sessions led to inconsistent authentication states [1][2]. Could you let us know if manually clearing the cookie resolves the issue, or if you have any custom cookie handling in your setup?

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

If you need more help, tag @better-auth-agent in a comment so I can respond.

DiagramDiscordGitHub

Diagram Join Star

<!-- gh-comment-id:3620612488 --> @better-auth-agent[bot] commented on GitHub (Dec 6, 2025): Hi there! It looks like the signOut issue after stopping impersonation is occurring because the admin session isn’t being completely cleared. This can leave a lingering admin_session cookie that interferes with the normal signOut process, resulting in a 307 redirect and a 400 error when attempting to get the session. A few troubleshooting steps you could try are: • Verify that you’re calling stopImpersonating before signOut, ensuring the session is fully terminated. • As a temporary workaround, try manually clearing the admin_session cookie after stopping impersonation. • Double-check your cookie configuration and prefix settings to ensure they’re applied consistently to both regular and admin sessions. These steps align with similar reported issues where improperly cleared admin sessions led to inconsistent authentication states [[1]](https://github.com/better-auth/better-auth/issues/6446)[[2]](https://github.com/better-auth/better-auth/issues/6228). Could you let us know if manually clearing the cookie resolves the issue, or if you have any custom cookie handling in your setup? tag @better-auth-agent if you would like an answer from the Agent. _If you need more help, tag @better-auth-agent in a comment so I can respond._ <!-- bot:webhook reply v1 --> [Diagram](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) • [Discord](https://discord.gg/fG2XXEuQX3) • [GitHub](https://github.com/Skyvern-AI/Skyvern) [![Diagram](https://img.shields.io/badge/Diagram-2b3137?style=flat-square)](https://repodiagrams.s3.eu-north-1.amazonaws.com/skyvern_ultra_detailed_interactive.html) [![Join](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&style=flat-square)](https://discord.gg/fG2XXEuQX3) [![Star](https://img.shields.io/badge/star-181717?logo=github&logoColor=white&style=flat-square)](https://github.com/Skyvern-AI/Skyvern)
Author
Owner

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

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

This is a known issue in Better Auth: after stopping impersonation, the admin_session cookie is not cleared by either stopImpersonating or signOut, which leaves the client in an inconsistent state and can cause sign-out failures or redirect loops (like error 307) source. The signOut endpoint only deletes the main session cookies and does not handle admin_session source.

The recommended workaround is to manually clear the admin_session cookie on the client after stopping impersonation and before or after calling signOut. In a Next.js/React app, you can do this with:

document.cookie = "better-auth.admin_session=; Max-Age=0; path=/";

If you use a custom cookie prefix or secure cookies, adjust the name accordingly (e.g., __Secure-better-auth.admin_session). This manual cleanup is needed until the SDK/plugin is updated to handle this automatically source.

Let me know if you need a more detailed code example for your specific setup.

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:3620615645 --> @dosubot[bot] commented on GitHub (Dec 6, 2025): <!-- Greeting --> Hi @Calyrex! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> This is a known issue in Better Auth: after stopping impersonation, the admin_session cookie is not cleared by either stopImpersonating or signOut, which leaves the client in an inconsistent state and can cause sign-out failures or redirect loops (like error 307) [source](https://github.com/better-auth/better-auth/blob/28e88609afcb0fe2ed777e2c71c8ee5ee4112fa7/packages/better-auth/src/plugins/admin/routes.ts#L938-L1131). The signOut endpoint only deletes the main session cookies and does not handle admin_session [source](https://github.com/better-auth/better-auth/blob/28e88609afcb0fe2ed777e2c71c8ee5ee4112fa7/packages/better-auth/src/api/routes/sign-out.ts#L34-L50). The recommended workaround is to manually clear the admin_session cookie on the client after stopping impersonation and before or after calling signOut. In a Next.js/React app, you can do this with: ```js document.cookie = "better-auth.admin_session=; Max-Age=0; path=/"; ``` If you use a custom cookie prefix or secure cookies, adjust the name accordingly (e.g., `__Secure-better-auth.admin_session`). This manual cleanup is needed until the SDK/plugin is updated to handle this automatically [source](https://github.com/better-auth/better-auth/issues/2185). Let me know if you need a more detailed code example for your specific setup. <!-- 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/241a0e0c-4134-4c6e-bf10-ddfbe2702c7d?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/241a0e0c-4134-4c6e-bf10-ddfbe2702c7d?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/241a0e0c-4134-4c6e-bf10-ddfbe2702c7d?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/241a0e0c-4134-4c6e-bf10-ddfbe2702c7d?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/241a0e0c-4134-4c6e-bf10-ddfbe2702c7d?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/241a0e0c-4134-4c6e-bf10-ddfbe2702c7d?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/241a0e0c-4134-4c6e-bf10-ddfbe2702c7d?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%20is%20a%20known%20issue%20in%20Better%20Auth%3A%20after%20stopping%20impersonation%2C%20the%20admin_session%20cookie%20is%20not%20cleared%20by%20either%20stopImpersonating%20or%20signOut%2C%20which%20leaves%20the%20client%20in%20an%20inconsistent%20state%20and%20can%20cause%20sign-out%20failures%20or%20redirect%20loops%20%28like%20error%20307%29%20%5Bsource%5D%28https%3A//github.com/better-auth/better-auth/blob/28e88609afcb0fe2ed777e2c71c8ee5ee4112fa7/packages/better-auth/src/plugins/admin/routes.ts%23L938-L1131%29.%20The%20signOut%20endpoint%20only%20deletes%20the%20main%20session%20cookies%20and%20does%20not%20handle%20admin_session%20%5Bsource%5D%28https%3A//github.com/better-auth/better-auth/blob/28e88609afcb0fe2ed777e2c71c8ee5ee4112fa7/packages/better-auth/src/api/routes/sign-out.ts%23L34-L50%29.%0A%0AThe%20recommended%20workaround%20is%20to%20manually%20clear%20the%20admin_session%20cookie%20on%20the%20client%20after%20stopping%20impersonation%20and%20before%20or%20after%20calling%20signOut.%20In%20a%20Next.js/React%20app%2C%20you%20can%20do%20this%20with%3A%0A%0A%60%60%60js%0Adocument.cookie%20%3D%20%22better-auth.admin_session%3D%3B%20Max-Age%3D0%3B%20path%3D/%22%3B%0A%60%60%60%0A%0AIf%20you%20use%20a%20custom%20cookie%20prefix%20or%20secure%20cookies%2C%20adjust%20the%20name%20accordingly%20%28e.g.%2C%20%60__Secure-better-auth.admin_session%60%29.%20This%20manual%20cleanup%20is%20needed%20until%20the%20SDK/plugin%20is%20updated%20to%20handle%20this%20automatically%20%5Bsource%5D%28https%3A//github.com/better-auth/better-auth/issues/2185%29.%0A%0ALet%20me%20know%20if%20you%20need%20a%20more%20detailed%20code%20example%20for%20your%20specific%20setup.)&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/6567)
Author
Owner

@daikiejp commented on GitHub (Dec 6, 2025):

Since you’re using Next.js, a temporary fix around: you can call a Server Action to delete the cookie on the server before call signOut. Just keep in mind that better-auth uses a cookie prefix, so you need to adjust the cookie name (better-auth.admin_session) to match your project configuration.

"use server";
import { cookies } from "next/headers";

export async function destroyAdminSession() {
  const cookieStore = await cookies();
  cookieStore.delete("better-auth.admin_session");
}
<!-- gh-comment-id:3620632235 --> @daikiejp commented on GitHub (Dec 6, 2025): Since you’re using Next.js, a temporary fix around: you can call a Server Action to delete the cookie on the server before call signOut. Just keep in mind that better-auth uses a cookie prefix, so you need to adjust the cookie name (better-auth.admin_session) to match your project configuration. ```typescript "use server"; import { cookies } from "next/headers"; export async function destroyAdminSession() { const cookieStore = await cookies(); cookieStore.delete("better-auth.admin_session"); } ```
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#10556