Roles & Permissions

UniAuth uses role-based access control (RBAC) to govern what each user can see and do across the platform. Every user is assigned a single role, and that role carries a set of granular permissions that determine access to admin features, API endpoints, and protected resources.

Overview

UniAuth ships with three built-in roles that cover the most common access patterns. Administrators can also create custom roles with tailored permission sets to match their organization's needs. Roles are stored in the roles table and referenced by name in each user record.

Built-in Roles

RoleDescriptionAccess Level
adminFull system accessCan manage all users, roles, sessions, OAuth clients, webhooks, analytics, and system settings. Can impersonate users and rotate OIDC keys.
moderatorRead-only management accessCan view users, sessions, activity logs, and dashboard statistics. Cannot modify accounts, change roles, or manage OAuth clients.
userStandard user (default)Self-service access only. Can manage their own profile, security settings, connected services, and register OAuth applications via the developer console.

Built-in roles are marked as system roles and cannot be deleted. However, administrators can modify their permission sets if the defaults do not fit their requirements.

Permissions

Permissions are stored as a JSON array on each role and follow a resource:action naming convention. The complete list of available permissions:

PermissionDescriptionAdminModerator
users:readView user list and detailsYesYes
users:writeModify user accounts (change role, lock/unlock)YesNo
users:deleteDelete user accountsYesNo
sessions:readView active sessionsYesYes
sessions:revokeRevoke any user's sessionsYesNo
logs:readView activity and audit logsYesYes
roles:readView roles and their permissionsYesNo
roles:writeCreate, modify, and delete custom rolesYesNo
stats:readView dashboard statistics and analyticsYesYes
settings:readView system configurationYesNo
settings:writeModify system settings (SMTP, branding, policies)YesNo
oauth:readView all registered OAuth clientsYesNo
oauth:writeCreate, modify, and delete OAuth clientsYesNo

Assigning Roles

Administrators can change a user's role from the admin panel:

  1. Navigate to Admin Panel → Users.
  2. Find the user by searching their email or name.
  3. Click on the user to open their detail view.
  4. Select the new role from the role dropdown.
  5. Save the changes. The user's next request will use the updated role.

Alternatively, use the API:

PUT /api/admin/users/:id
Content-Type: application/json

{
  "role": "moderator"
}

// Response:
{
  "success": true,
  "user": {
    "id": "uuid",
    "email": "[email protected]",
    "role": "moderator"
  }
}

Note: Role changes take effect on the user's next authenticated request. Existing session tokens contain the previous role until they are refreshed or the user signs in again.

Role in JWT Tokens

The user's role is embedded in their session JWT, making it available for server-side authorization checks without additional database queries. The JWT payload includes:

{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "email": "[email protected]",
  "firstName": "Jane",
  "lastName": "Admin",
  "role": "admin",
  "iat": 1700000000,
  "exp": 1700604800
}

This allows your application code or middleware to make authorization decisions based on the role claim without hitting the database on every request.

Custom Roles

The three built-in roles cover common scenarios, but many organizations need more granular control. Administrators can create custom roles with specific permission sets.

Creating a Custom Role

Navigate to Admin Panel → Roles and click Create Role, or use the API:

POST /api/admin/roles
Content-Type: application/json

{
  "name": "support",
  "description": "Support team — can view users and logs but cannot modify accounts",
  "permissions": ["users:read", "logs:read", "sessions:read"]
}

// Response:
{
  "success": true,
  "role": {
    "id": "uuid",
    "name": "support",
    "description": "Support team — can view users and logs but cannot modify accounts",
    "permissions": ["users:read", "logs:read", "sessions:read"],
    "is_system": false
  }
}

Example Custom Roles

Role NameUse CasePermissions
supportCustomer support teamusers:read, logs:read, sessions:read
developerInternal developers managing OAuth appsoauth:read, oauth:write, stats:read
auditorCompliance and security auditingusers:read, sessions:read, logs:read, stats:read, settings:read

Middleware Protection

All routes under /admin/* are automatically protected by the UniAuth middleware. The middleware performs two checks:

  1. Authentication — The request must include a valid session cookie. Unauthenticated requests are redirected to the login page.
  2. Role check — The user's role (from the JWT) must be admin or moderator. Users with insufficient permissions receive a 403 response.

This protection runs at the edge before your page or API handler executes, so unauthorized requests are blocked with minimal latency.

API Role Checks

In addition to middleware-level protection, individual API route handlers verify the caller's role using the verifyAdmin() helper function. This provides defense in depth:

// Example: Admin API route handler
import { verifyAdmin } from "@/lib/admin";
import { successResponse, errorResponse } from "@/lib/api-response";

export async function GET(request: Request) {
  // verifyAdmin() checks the session cookie and confirms
  // the user has admin or moderator role
  const adminUser = await verifyAdmin();
  if (!adminUser) {
    return errorResponse("Unauthorized", 403);
  }

  // Proceed with admin-only logic
  const data = await fetchSensitiveData();
  return successResponse(data);
}

For more granular checks, you can inspect the user's specific permissions by loading the role from the database and checking the permissions array.

Promoting the First Admin

When you first deploy UniAuth, all users are created with the default user role. To bootstrap the admin panel, you need to promote your first administrator directly in the database:

-- Promote your account to admin
UPDATE users SET role = 'admin' WHERE email = '[email protected]';

After this initial promotion, the first admin can manage all other users' roles through the admin panel UI or API without further database access.

Tip: After promoting the first admin, sign out and sign back in so that the new role is reflected in your session token.