BETTER-AUTH. UI
Plugins

Admin

Add static user management, session details, and impersonation to Solid and Zaidan.

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

Setup

Enable the Better Auth admin plugin

src/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 Solid client plugin

src/lib/auth-client.ts
import { createAuthClient } from "@better-auth-ui/solid"
import { adminClient } from "better-auth/client/plugins"

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

Install the Solid and Zaidan integration

npx shadcn@latest add https://better-auth-ui.com/r/solid/admin.json

This copies:

  • 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 copied UI plugin

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

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

Add the users route

Create one static TanStack Start route:

src/routes/admin/users.tsx
import { createFileRoute } from "@tanstack/solid-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 supplies the final static path segment. The user-detail dialog keeps user IDs out of the route contract.

Applications can control the selected user through <AdminUsers />:

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

<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 dialog 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 either email or name in each request. Passwords stay in local form state. The forms clear each password after the request or when the user closes the form. Session IP addresses are hidden unless showIpAddress is true.

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

The copied 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/solid/plugins/admin"

const stopImpersonating = useStopImpersonating(authClient)

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

See the Solid package reference for the shared query and mutation APIs.

Last updated on

On this page