Admin
Add static user management, session details, 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:
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
import { createAuthClient } from "better-auth/react"
import { adminClient } from "better-auth/client/plugins"
export const authClient = createAuthClient({
plugins: [adminClient()]
})Register the UI plugin
import { AuthProvider } from "@better-auth-ui/heroui"
import { adminPlugin } from "@better-auth-ui/heroui/plugins"
<AuthProvider
authClient={authClient}
navigate={navigate}
plugins={[adminPlugin()]}
>
{children}
</AuthProvider>Add the users route
Create one static route for the users page:
import { Admin } from "@better-auth-ui/heroui"
export default function AdminUsersPage() {
return <Admin view="users" />
}Use <Admin path="users" /> when a parent route passes the final static path
segment. The user-detail drawer keeps user IDs out of the route contract.
Applications can control the drawer through <AdminUsers />:
<AdminUsers
selectedUserId={selectedUserId}
onSelectedUserIdChange={setSelectedUserId}
/>Inspector tabs
The user 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.
User actions
The users page can create users. The drawer can update a user's name and role, set a password, ban or unban the user, impersonate the user, delete the user, and revoke one or all of the user's sessions.
The UI checks the matching Admin client permission before it enables each action. Dangerous actions require confirmation. The UI also disables actions that would ban, delete, impersonate, or revoke sessions for the current user.
Permissions and privacy
The users page calls the Better Auth permission API before it requests the user list. Do not authorize the page from a role string alone.
The table searches one field per request. The supported fields are email
and name.
Passwords stay in local form state and never enter query keys. The forms clear
each password after the request or when the user closes the form. Session IP
addresses are hidden unless showIpAddress is true.
Configure custom roles with the same names in Better Auth and the UI plugin:
adminPlugin({
allowMultipleRoles: false,
defaultRole: "member",
impersonationRedirectTo: "/",
pageSize: 25,
roles: ["member", "support", "admin"],
showIpAddress: false
})Set allowMultipleRoles to false to make the create and edit forms accept
one role. This option does not change adminRoles, which controls administrator
access.
The public Admin client does not provide account disconnection, global organization administration, or a Sentinel dashboard. These views are not part of this integration.
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 "@better-auth-ui/heroui/plugins"
<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