Users Management
The Users section (/dashboard/users) gives administrators a centralized view over all registered user accounts, including the ability to assign and manage roles.
Accessing the Users management pages requires user.read permission. Assigning roles requires user.write or roles.manage.
Data Model
interface User {
id: string;
name: string;
email: string;
image: string | null;
emailVerified: boolean;
createdAt: string;
userRoles: {
id: number;
userId: string;
roleId: number;
role: Role;
}[];
}
interface Role {
id: number;
name: string; // e.g., 'admin', 'manager'
label: string; // Display name: 'Administrator'
}API Endpoints
| Method | Endpoint | Permission | Description |
|---|---|---|---|
GET | /api/users | user.read | List all users with their roles |
POST | /api/users/[id]/roles | user.write | Assign a single role to a user |
PUT | /api/users/[id]/roles/batch | user.write | Sync multiple roles (replaces all current roles) |
POST | /api/users/[id]/sync-roles | roles.manage | Sync Better Auth sessions with current DB roles |
Frontend API Client
Use usersApi from src/services/users/api.ts:
import { usersApi } from '@/services/users/api';
// Fetch all users (includes roles)
const { data: users } = await usersApi.getUsers();
// Assign a single role
await usersApi.assignRole(userId, roleId);
// Replace ALL roles for a user atomically
await usersApi.syncUserRoles(userId, [2, 4]); // array of roleIdsDashboard UI
The Users page provides:
- A paginated data table with search by name or email
- Role badge(s) displayed inline per user
- Assign Role dialog — select from all available roles; uses
syncUserRolesto atomically replace the current role set - User detail card — shows avatar, email, join date, and active sessions
Role Assignment
Role changes take effect on the user’s next API request. Since Better Auth caches sessions, the user may need to refresh or the session will update on the next automatic refresh cycle (every 24h by default, configurable in auth.ts).
For immediate propagation, use the sync endpoint:
// Force Better Auth to re-issue the session with updated roles
await usersApi.syncUserRoles(userId, newRoleIds);
// then call the sync endpoint:
await fetch(`/api/users/${userId}/sync-roles`, { method: 'POST' });Role Hierarchy Enforcement
The canManageRole() helper from src/lib/role-hierarchy.ts prevents privilege escalation:
// src/app/api/users/[id]/roles/route.ts
import { canManageRole } from '@/lib/role-hierarchy';
const targetRole = await prisma.role.findUnique({ where: { id: roleId } });
const actorRoleName = session.user.roles?.[0] ?? 'guest';
if (!canManageRole(actorRoleName, targetRole!.name)) {
return NextResponse.json(
{ error: 'You cannot assign a role equal to or higher than your own.' },
{ status: 403 }
);
}super_admin is the only role that can assign the admin role to other users. An admin can assign manager, user, and guest roles.