BETTER-AUTH. UI
Plugins

Admin

Add static user management, session controls, and impersonation to an administration area.

The Admin plugin adds a static /admin/users page and a user-detail drawer. It also adds a "Stop impersonating" action to <UserButton />.

Setup

Enable the Better Auth admin plugin

Add admin() to the server configuration:

lib/auth.ts
import { betterAuth } from "better-auth"
import { admin } from "better-auth/plugins"

export const auth = betterAuth({
  // ...
  plugins: [
    admin() 
  ]
})

Update your database schema after enabling the plugin. Better Auth adds admin fields to users and an impersonatedBy field to sessions.

Add the matching client plugin

Add adminClient() so the UI can read the impersonation marker and restore the administrator's session:

lib/auth-client.ts
import { createAuthClient } from "better-auth/react"
import { adminClient } from "better-auth/client/plugins"

export const authClient = createAuthClient({
  plugins: [adminClient()] 
})

Install the UI integration

npx shadcn@latest add @better-auth-ui/admin

This installs:

  • src/lib/auth/auth-plugin.ts
  • src/lib/auth/admin-plugin.ts
  • src/components/auth/admin/admin.tsx
  • src/components/auth/admin/admin-users.tsx
  • src/components/auth/admin/stop-impersonating.tsx

Register the UI plugin

components/providers.tsx
import { AuthProvider } from "@/components/auth/auth-provider"
import { adminPlugin } from "@/lib/auth/admin-plugin"

<AuthProvider
  authClient={authClient}
  navigate={navigate}
  plugins={[adminPlugin()]} 
>
  {children}
</AuthProvider>

Add the users route

Create one static route for the users page. The drawer keeps user IDs out of the route contract.

app/admin/users/page.tsx
import { Admin } from "@/components/auth/admin/admin"

export default function AdminUsersPage() {
  return <Admin view="users" />
}

TanStack Start can use the same component in routes/admin/users.tsx:

import { createFileRoute } from "@tanstack/react-router"
import { Admin } from "@/components/auth/admin/admin"

export const Route = createFileRoute("/admin/users")({
  component: () => <Admin view="users" />
})

Use <Admin path="users" /> when a parent route passes the final static path segment. Applications can control the drawer without changing this route:

import { AdminUsers } from "@/components/auth/admin/admin-users"

<AdminUsers
  selectedUserId={selectedUserId}
  onSelectedUserIdChange={setSelectedUserId}
/>

This API lets an application connect search parameters later. Search parameters are not required by the library.

Permissions

The users page calls the Better Auth permission API before it requests the user list. Each server endpoint remains the final security boundary.

Do not authorize this page from a role string alone. Better Auth also supports custom roles, custom permissions, and adminUserIds.

The table searches one field per request. Select Email or Name before you enter a search value. The public Admin API does not provide one combined search across names, email addresses, and user IDs.

User inspector

Select a row to open the user inspector. The inspector includes local Overview and Sessions tabs. Registered plugins can add more tabs without adding routes.

The Dash integration adds an Activity tab when both UI plugins are registered. Dash applies its own organization owner or admin access rules to this tab.

The users page can create users. The inspector can update names and roles, set passwords, ban or unban users, impersonate users, remove users, and revoke one or all sessions. Dangerous actions require confirmation. The UI disables self-destructive actions and still relies on the server.

Passwords stay in local form state. The forms clear each password after the request or after the user closes the form.

Session IP addresses are hidden by default. Set showIpAddress: true only when your privacy policy permits this data.

Custom roles and options

adminPlugin({
  allowMultipleRoles: false,
  defaultRole: "member",
  impersonationRedirectTo: "/",
  pageSize: 25,
  roles: ["member", "support", "admin"],
  showIpAddress: false
})

Configure the same roles and permissions in Better Auth admin() and adminClient(). The UI list only controls which role choices it shows.

Set allowMultipleRoles to false to make the create and edit forms accept one role. This option does not change adminRoles, which controls administrator access.

Scope

This integration uses the public Better Auth Admin client. It does not add account disconnection, organization membership management, global organization administration, analytics, or a Sentinel dashboard.

User button behavior

adminPlugin() contributes <StopImpersonating /> through the userMenuItems slot. <UserButton /> places it above sign out.

The action renders only when session.session.impersonatedBy is present. Selecting it calls authClient.admin.stopImpersonating() and refreshes the cached session before the pending state completes.

import { StopImpersonating } from "@/components/auth/admin/stop-impersonating"

<StopImpersonating />

Prop

Type

Options

adminPlugin({
  localization: {
    stopImpersonating: "Return to admin"
  }
})

Prop

Type

Localization

Prop

Type

Mutation API

import { useStopImpersonating } from "@better-auth-ui/react/plugins/admin"

const stopImpersonating = useStopImpersonating(authClient)

Use the hook when you need the same behavior outside the user button. It restores the admin session and awaits invalidation of the shared session query.

Last updated on

On this page