Better Auth impersonation: what support teams need to add

How the Better Auth admin plugin handles impersonation: permissions, stopImpersonating, common errors, and what support teams add for approvals and scope.

Yes, Better Auth supports user impersonation through its admin plugin (opens in a new tab). An admin calls impersonateUser to “log in as” a customer and stopImpersonating to return to their own account. If your support team only needs that, start there.

The plugin decides whether a signed-in admin can impersonate. It doesn’t decide which customers a support agent should open, why, for how long, or what they may change once inside. This guide covers the native behavior and what your application adds on top.

What the admin plugin provides

  • Endpoints. impersonateUser (POST /admin/impersonate-user) and stopImpersonating (POST /admin/stop-impersonating), available from the client as authClient.admin.* and from the server as auth.api.*.
  • Permission checks. The admin plugin docs (opens in a new tab) say the caller must be authenticated with an account whose role has the impersonate permission. You can define custom roles with createAccessControl.
  • Admin protection. By default admins can’t impersonate other admins. Grant impersonate-admins to a role to allow it. The older allowImpersonatingAdmins option is deprecated.
  • Session length. One hour by default, set with impersonationSessionDuration. The session is non-persistent, so it also ends when the browser session ends.
  • Attribution. The impersonated session row stores impersonatedBy, the admin’s user ID.

How restoration works: when impersonation starts, Better Auth keeps the admin’s session token in a signed admin_session cookie. stopImpersonating deletes the impersonated session and restores the admin session from that cookie. If the cookie is missing, points to an admin session that no longer exists, or belongs to a different user than impersonatedBy, the plugin’s source code (opens in a new tab) fails the call with “Failed to find admin session”. Cookie settings, subdomains and proxies all affect this, so test it in your real deployment.

Besides impersonatedBy, the plugin has no impersonation audit trail or approval step. Those are yours to build or bring.

Common Better Auth impersonation errors

Most “impersonation not working” threads come down to three messages defined in the admin plugin source (opens in a new tab):

MessageUsual cause
”You are not allowed to impersonate users”The caller’s role doesn’t grant impersonate. The plugin reads the role stored on the user and checks it against the roles you passed to the plugin, unless the user is listed in adminUserIds.
”You cannot impersonate admins”The target has an admin role, and the caller lacks impersonate-admins.
”Failed to find admin session”stopImpersonating couldn’t restore the staff session from the admin_session cookie.

If you defined custom roles, pass them to the admin plugin on the server. A role that exists only in your own code won’t satisfy the check.

Give support a narrow role

Don’t make support agents full admins just so the impersonate button works. Create a support role with impersonate and only the other permissions it truly needs. Keep these as separate decisions:

  • Impersonating an ordinary customer.
  • Impersonating an admin or privileged account (impersonate-admins).
  • Changing roles, banning users, or managing sessions and credentials.

Also check business eligibility before calling impersonateUser. Is this customer assigned to this agent? Is the account active? Is it an internal or excluded account? A user ID from the browser doesn’t answer any of these. The assigned-customer guide covers these checks.

During the session, keep the customer’s normal permissions. If support sees a feature only because its own role bypasses authorization, the investigation won’t explain the customer’s problem.

When the native plugin is enough

The admin plugin alone can work well if:

  • A few trusted staff impersonate occasionally.
  • Your backend already checks impersonatedBy and blocks risky operations during impersonated sessions.
  • The one-hour default, or your own value, fits your investigations.
  • You log the admin ID next to the customer ID for any change made while impersonating.
  • You don’t need per-request approval, a recorded reason or a separate access history.

Try lighter options first. A staging fixture often reproduces a generic bug, and a backend denial log can explain a permission problem without opening the account.

How Devora fits with Better Auth

Devora adds the workflow around impersonation: access requests with a reason, approval by an approver or admin in your organization, read-only or read-and-write scope, a time limit and access history. Better Auth still creates the browser session, as Devora’s auth provider overview (opens in a new tab) explains.

Three requirements from the Devora Better Auth guide (opens in a new tab) shape the integration:

The staff member must already be signed in to your app. They need an existing Better Auth session with impersonation permission. Signing in to Devora doesn’t replace that. If support staff don’t have accounts in your app, look at the custom one-time session bridge (opens in a new tab) instead.

You add a small binding route. Better Auth’s impersonation endpoint doesn’t accept extra context, so Devora’s verified context has to be attached afterwards. Devora doesn’t ship a packaged helper for this. Your route should:

  1. Authenticate the newly impersonated session and confirm it is impersonating.
  2. Consume a short-lived, one-time handle from your backend.
  3. Check that the handle’s target matches the session’s user and that impersonatedBy is set. We also recommend checking that impersonatedBy maps to the approved staff member.
  4. Store the verified context against that session unchanged, so the backend guard can read it on each request.
StepOwner
Approve the request: actor, target, scope, time windowDevora
Authenticate staff and create the impersonated sessionBetter Auth, with your role configuration
Hold verified context behind a one-time handleYour backend
Bind the context to the impersonated sessionYour binding route
Enforce scope plus normal tenant checksDevora backend guard, plus your authorization
End access and clean upYour application, triggered by Devora’s lifecycle events

Close the gap between session creation and binding. Between impersonateUser and a successful binding, an impersonated session exists without Devora context. If your context function returns nothing, Devora’s Node scope guard (opens in a new tab) treats the request as ordinary traffic. So your app must treat “impersonatedBy is set but no binding exists” as denied, and clean up the session if binding fails. Test this failure path before the happy path.

Expiry and restoration

Keep impersonationSessionDuration no longer than the longest Devora session you allow. The Better Auth guide (opens in a new tab) notes that the backend guard also checks each session’s own expiry, so a short approval is enforced even if the Better Auth session would last longer.

When access ends with the tab open, the Devora callback calls stopImpersonating. Confirm it really returns the staff account, given what can make the admin_session cookie restore fail. If it fails, send the user to sign-in rather than leaving the customer session active.

A browser callback can’t run after the tab closes. Handle Devora’s signed termination notice (opens in a new tab) on your server and revoke the impersonated session there.

Test it in staging

Record your Better Auth version and use synthetic accounts. These are the outcomes to look for:

TestPass condition
Staff role lacks impersonateNo customer session is created
Support role targets an admin accountDenied unless impersonate-admins and your policy allow it
Handle reused, expired or bound to the wrong userBinding fails; protected requests stay denied
impersonatedBy doesn’t match the approved staff memberBinding rejected
Binding fails after the session is createdNo unrestricted access; session cleaned up
Read-only session sends a write directly to the APIBackend rejects it; data unchanged
Access ends with the tab open, and with it closedCustomer access stops; staff session restored or sent to sign-in

Follow the Devora testing guide (opens in a new tab) and record API responses and server-side session state, not just what the browser shows. Use the native plugin alone if it meets your requirements. If you need approvals, scoped access and access history, and you can own the binding route, create a Devora account and evaluate one staging investigation. The build vs buy guide can help with that decision.

Sources

Quick answers

Common questions, answered clearly.

Direct answers to the questions teams usually ask when evaluating this approach.

Does Better Auth support impersonation?

Yes. The admin plugin provides impersonateUser to start an impersonated session and stopImpersonating to return to the admin account. The caller must already be signed in with a role that has the impersonate permission.

Can support have limited impersonation permission?

Yes. Use createAccessControl to define a support role with the impersonate permission and nothing else it does not need. Impersonating other admins is a separate permission, impersonate-admins, which is not granted by default.

Why does Better Auth say "You are not allowed to impersonate users"?

The signed-in user's role doesn't grant the impersonate permission. Better Auth checks the role stored on the user against the roles passed to the admin plugin, or the adminUserIds list. Check the user's role value and make sure any custom roles are configured on the server plugin.

How long does a Better Auth impersonation session last?

One hour by default, configurable with impersonationSessionDuration. It is a non-persistent session, so it also ends when the browser session ends.

How does the staff session get restored?

stopImpersonating deletes the impersonated session and restores the admin session from a signed admin_session cookie. If that cookie is missing or doesn't match, the call fails, so give staff a safe way to sign in again.

Does Devora ship a Better Auth binding helper?

No. Devora's Better Auth recipe requires your application to add a small binding route that consumes a one-time handle and attaches Devora's verified context to the impersonated session.

Put it into practice

Give your team context.Keep control of access.

Bring approvals, scoped sessions, and access history into your support workflow.