Admin Plugin

User management, role-based access control, banning, and impersonation for administrators.

This guide is part of the Drizzle stack docs.

Manage users from an admin dashboard. The admin plugin provides role-based access control, user banning, session management, and impersonation for support and debugging.

This page is part of the Authentication documentation.

Overview

The admin plugin extends Better Auth with administrative capabilities:

  • Role-based access control (RBAC) - Define admin roles with specific permissions
  • User management - View, search, and manage all users
  • Banning - Temporarily or permanently ban users
  • Impersonation - Sign in as another user for support
  • Session control - Revoke user sessions

Configuration

The admin plugin is configured in packages/better-auth/src/plugins/admin.ts:

import { admin } from 'better-auth/plugins/admin';
import { userAc } from 'better-auth/plugins/admin/access';
import {
adminAc,
adminRoles,
getAdminRoleNames,
} from '@kit/rbac/admin';
import { DEFAULT_ROLE } from './admin-config';
const IMPERSONATION_SESSION_DURATION = 60 * 60; // 1 hour
const DEFAULT_BAN_EXPIRES_IN = undefined; // Permanent
function buildRolesConfig() {
const roles = { user: userAc };
for (const [roleName, role] of Object.entries(adminRoles)) {
roles[roleName] = role;
}
return roles;
}
export const adminPlugin = admin({
defaultRole: DEFAULT_ROLE,
adminRoles: getAdminRoleNames(),
impersonationSessionDuration: IMPERSONATION_SESSION_DURATION,
defaultBanExpiresIn: DEFAULT_BAN_EXPIRES_IN,
ac: adminAc,
roles: buildRolesConfig(),
});

RBAC Configuration

Admin roles are defined in packages/rbac/src/admin-rbac.config.ts via defineAdminRBACConfig(). The kit ships a single admin role:

RoleHierarchy levelDescription
userRegular user (non-admin), Better Auth's defaultRole
admin100Full administrative access (every action on every resource)

Higher hierarchy numbers mean more authority. There is no super-admin role by default: admin already holds all permissions.

Resources and Actions

The default access controller (packages/rbac/src/admin/defaults.ts) defines these resources and actions. The user and session names must match Better Auth exactly:

ResourceActions
usercreate, list, get, update, set-role, set-password, ban, impersonate, delete
sessionlist, revoke, delete
organizationslist, view
dashboardview

Note the exact names: there is no read (use get or list) and no revokeAll (use revoke). ban covers both ban and unban.

Customizing Admin Roles

Edit packages/rbac/src/admin-rbac.config.ts to add roles, resources, or actions:

import { defineAdminRBACConfig } from './admin/factory';
export default defineAdminRBACConfig({
// Custom roles with hierarchy levels (admin: 100 is always present)
roles: {
support: 50,
moderator: 30,
},
// Optional: extra resources and the actions they accept
resources: {
SUBSCRIPTIONS: 'subscriptions',
},
actions: {
REFUND: 'refund',
},
accessController: {
subscriptions: ['list', 'view', 'refund'],
},
// Permissions per role. 'admin' gets everything unless overridden.
permissions: {
support: {
user: ['list', 'get', 'ban'],
session: ['list', 'revoke'],
organizations: ['list', 'view'],
dashboard: ['view'],
subscriptions: ['list'],
},
moderator: {
user: ['list', 'get', 'ban'],
dashboard: ['view'],
},
},
});

The factory validates the compiled config and throws AdminRBACConfigError at import time on duplicate resource/action values, permissions using actions missing from the access controller, or permissions defined for roles missing from the hierarchy.

Custom accessController entries are unioned with the defaults, so listing a subset of a default resource's actions adds to them and never removes them. adminAc and adminRoles (consumed by the admin plugin above) are derived from this compiled config.

Admin Dashboard

The admin panel is available at /admin for users with admin roles. Features include:

  • User list - Paginated view of all users
  • User search - Find users by email or name
  • User details - View account information, sessions, organizations
  • User actions - Ban, unban, impersonate, revoke sessions

See the Admin Overview documentation for detailed admin panel usage.

User Management

Listing Users

import { authClient } from '@kit/better-auth/client';
const { data: users } = await authClient.admin.listUsers({
limit: 20,
offset: 0,
sortBy: 'createdAt',
sortOrder: 'desc',
});

Searching Users

const { data: results } = await authClient.admin.listUsers({
searchField: 'email',
searchValue: 'user@example.com',
});

Banning Users

Ban a User

import { authClient } from '@kit/better-auth/client';
// Permanent ban
await authClient.admin.banUser({
userId: 'user-id',
reason: 'Violation of terms of service',
});
// Temporary ban (7 days)
await authClient.admin.banUser({
userId: 'user-id',
reason: 'Suspicious activity',
expiresIn: 7 * 24 * 60 * 60, // seconds
});

Unban a User

await authClient.admin.unbanUser({
userId: 'user-id',
});

Ban Behavior

When banned:

  • User's active sessions are revoked
  • User cannot sign in
  • User sees a "banned" message on sign-in attempt
  • Temporary bans auto-expire

Impersonation

Impersonation allows admins to sign in as another user for support and debugging without knowing their password.

Start Impersonation

import { authClient } from '@kit/better-auth/client';
await authClient.admin.impersonateUser({
userId: 'user-id',
});
// Now signed in as that user
// Session duration: 1 hour (configurable)

Stop Impersonation

await authClient.admin.stopImpersonation();
// Returns to admin account

Impersonation Safety

  • Impersonation sessions expire after 1 hour
  • Actions during impersonation are logged
  • The impersonated session is clearly marked
  • Cannot impersonate other admins (configurable)

Session Management

View User Sessions

const { data: sessions } = await authClient.admin.listUserSessions({
userId: 'user-id',
});
// Returns: session ID, device info, IP, created at, last active

Revoke a Session

await authClient.admin.revokeSession({
sessionId: 'session-id',
});

Revoke All Sessions

await authClient.admin.revokeUserSessions({
userId: 'user-id',
});

Role Assignment

Set User Role

await authClient.admin.setRole({
userId: 'user-id',
role: 'admin',
});

Check User Role

import { isAdminRole } from '@kit/better-auth/admin-config';
const user = await authClient.getSession();
if (isAdminRole(user?.data?.user?.role)) {
// User has admin privileges
}

Client-Side Role Checks

The admin-config.ts exports utilities for role checking:

import {
ADMIN_ROLES,
isAdminRole,
roleHasPermission,
getRolePermissions,
} from '@kit/better-auth/admin-config';
// Check if role is an admin role (any role in the admin hierarchy)
if (isAdminRole('admin')) {
// true
}
// Check specific permission
if (roleHasPermission('admin', 'user', 'ban')) {
// Admin can ban users
}
// Get all permissions for a role
const permissions = getRolePermissions('admin');

Security Considerations

  • Principle of least privilege - Assign minimal necessary permissions
  • Audit logging - Log all admin actions for accountability
  • Two admin rule - Consider requiring multiple admins for destructive actions
  • Impersonation limits - Restrict what actions can be taken while impersonating

Common Pitfalls

  • Missing role checks in UI - Always check permissions before showing admin features.
  • Impersonation without logging - Ensure impersonation actions are auditable.
  • Overly permissive roles - Start restrictive and add permissions as needed.
  • Forgetting client plugin - Add adminClient() to auth-client.ts for client-side admin methods.

Frequently Asked Questions

How do I create the first admin user?
Use the database directly to set a user's role to 'admin' (the only admin role shipped by default). After that, existing admins can promote other users.
Can I customize what admins can impersonate?
Yes. Modify the RBAC configuration to control which roles can impersonate and which roles can be impersonated.
How do I audit admin actions?
Implement logging in your admin action handlers. The kit includes logging infrastructure you can extend.
Can I have multiple admin levels?
Yes. Add roles with their own hierarchy levels and permission sets in admin-rbac.config.ts, alongside the built-in 'admin' (level 100). Common additions are support and moderator.
What happens to a user's data when banned?
Banning only prevents sign-in. User data remains intact. For data deletion, use account deletion which triggers cleanup hooks.

For detailed admin panel documentation, see Admin Overview.