Overview
Domma CMS uses JWT-based authentication for all admin operations. The role-and-permission system allows granular access control across 11 resource types. Authentication is handled server-side by Fastify routes, with tokens stored in localStorage on the client.
Login Flow
The login sequence follows a standard JWT handshake with automatic silent refresh.
- User visits
/admin— redirected to login if not authenticated - Enter email and password —
POST /api/auth/login - Server validates credentials (bcrypt compare) — returns
{ accessToken, refreshToken } - Access token stored in localStorage; refresh token stored in an httpOnly cookie
- Subsequent requests include
Authorization: Bearer {token}header - Access token expires in 15 minutes; auto-refreshed using refresh token (7 days)
Registration (First-Run Setup)
Registration is intentionally restricted to prevent unauthorised account creation on production sites.
- Registration is disabled by default after initial setup
- First admin account created via
npm run setupinteractive wizard - Additional users created by admins: Admin → Users → New User
- Optional: enable self-registration in config (
auth.allowRegistration: true) - When enabled, users self-register at
/registerwith email verification (if SMTP is configured) - New self-registered users are assigned the
subscriberrole by default
auth.allowRegistration set to false unless you specifically need a self-service sign-up flow. Enabling it on a public site without email verification exposes the admin area to spam accounts.
Forgot / Reset Password
Password resets use a time-limited, single-use token delivered by email. SMTP must be configured in site settings for this flow to work.
- User clicks "Forgot password" on the login page
- Enter email address —
POST /api/auth/forgot-password - If the email exists, the server sends a reset email with a time-limited token (1 hour)
- User clicks the link — token is validated — user sets a new password
- All existing sessions are invalidated immediately on password reset
- Requires SMTP configured under Admin → Settings → Email
JWT Tokens
Domma CMS uses a two-token system to balance security (short-lived access) with usability (transparent refresh).
- Short-lived — 15 minutes
- Carries:
userId,email,role,iat,exp - Stored in localStorage
- Sent with every API request as a Bearer token
- Long-lived — 7 days
- Stored as an httpOnly cookie (not accessible via JS)
- Used only to obtain new access tokens silently
- Rotated on each use
The JWT_SECRET is generated automatically during the npm run setup wizard and stored in your .env file. Rotate it by regenerating and restarting — all active sessions will be invalidated.
Token payload example: { "userId": "abc123", "email": "admin@example.com", "role": "admin", "iat": 1700000000, "exp": 1700000900 }
Four Built-in Roles
Built-in roles cover the most common team structures. Each role is cumulative — higher roles include all permissions of roles below them.
| Role | Slug | Description |
|---|---|---|
| admin | admin |
Full access to everything: all content, all users, all settings, and all admin features. Cannot be deleted. |
| manager | manager |
Manage all content (pages, collections, forms, media, blocks) but not user management or system settings. |
| editor | editor |
Create and edit content (pages, media) but not delete or manage collections/forms. |
| subscriber | subscriber |
Read-only access to the admin dashboard; primarily used for members-only content on the public site. |
Custom Roles
Custom roles let you define exactly the right access level for your team without over-provisioning permissions.
Creating a Custom Role
- Navigate to Admin → Roles → New Role
- Enter a role name and slug (e.g. Content Reviewer /
content-reviewer) - Configure permissions per resource (11 resources × 4 actions = 44 flags)
- Save the role
Assigning a Custom Role
- Navigate to Admin → Users
- Select the user to update
- Open the Edit User panel
- Change the Role dropdown to your custom role
- Save — changes take effect on the user's next request
Permission Registry (11 Resources × 4 Actions)
Every admin action is governed by a permission flag. The table below shows the default grants for each built-in role.
| Resource | Action | admin | manager | editor | subscriber |
|---|---|---|---|---|---|
| pages | create | ✓ | ✓ | ✓ | ✗ |
| read | ✓ | ✓ | ✓ | ✓ | |
| update | ✓ | ✓ | ✓ | ✗ | |
| delete | ✓ | ✓ | ✗ | ✗ | |
| media | create | ✓ | ✓ | ✓ | ✗ |
| read | ✓ | ✓ | ✓ | ✓ | |
| update | ✓ | ✓ | ✓ | ✗ | |
| delete | ✓ | ✓ | ✗ | ✗ | |
| collections | create | ✓ | ✓ | ✗ | ✗ |
| read | ✓ | ✓ | ✓ | ✗ | |
| update | ✓ | ✓ | ✗ | ✗ | |
| delete | ✓ | ✓ | ✗ | ✗ | |
| forms | create | ✓ | ✓ | ✗ | ✗ |
| read | ✓ | ✓ | ✓ | ✗ | |
| update | ✓ | ✓ | ✗ | ✗ | |
| delete | ✓ | ✓ | ✗ | ✗ | |
| blocks | create | ✓ | ✓ | ✗ | ✗ |
| read | ✓ | ✓ | ✓ | ✗ | |
| update | ✓ | ✓ | ✗ | ✗ | |
| delete | ✓ | ✓ | ✗ | ✗ | |
| views Pro | create | ✓ | ✓ | ✗ | ✗ |
| read | ✓ | ✓ | ✓ | ✗ | |
| update | ✓ | ✓ | ✗ | ✗ | |
| delete | ✓ | ✓ | ✗ | ✗ | |
| actions Pro | create | ✓ | ✓ | ✗ | ✗ |
| read | ✓ | ✓ | ✓ | ✗ | |
| update | ✓ | ✓ | ✗ | ✗ | |
| delete | ✓ | ✓ | ✗ | ✗ | |
| settings | create | ✓ | ✗ | ✗ | ✗ |
| read | ✓ | ✗ | ✗ | ✗ | |
| update | ✓ | ✗ | ✗ | ✗ | |
| delete | ✓ | ✗ | ✗ | ✗ | |
| navigation | create | ✓ | ✓ | ✗ | ✗ |
| read | ✓ | ✓ | ✓ | ✗ | |
| update | ✓ | ✓ | ✗ | ✗ | |
| delete | ✓ | ✓ | ✗ | ✗ | |
| plugins | create | ✓ | ✗ | ✗ | ✗ |
| read | ✓ | ✓ | ✗ | ✗ | |
| update | ✓ | ✗ | ✗ | ✗ | |
| delete | ✓ | ✗ | ✗ | ✗ | |
| users | create | ✓ | ✗ | ✗ | ✗ |
| read | ✓ | ✗ | ✗ | ✗ | |
| update | ✓ | ✗ | ✗ | ✗ | |
| delete | ✓ | ✗ | ✗ | ✗ |
Pro resources (views, actions) are available on Pro and Enterprise plans. Custom roles can be configured with any combination of the above 44 flags.
User Profiles
Every authenticated user has an extended profile beyond their core auth fields. Profiles are stored as a preset collection linked to the auth user record by userId.
Profile Fields
displayName— public-facing namebio— short biography (textarea)avatar— media picker (linked to Media Library)website— personal or professional URLsocialLinks— object of platform → URL pairslocation— city / country free text
Accessing Profiles
- Admin UI: Users → [User] → Profile tab
- API:
GET /api/users/{id}/profile - Templates:
{{user.profile.*}}on auth-gated pages - Users can edit their own profile under Account Settings
- Admins can edit any user's profile
requiresAuth: true configured. On public pages, {{user.profile.*}} variables resolve to empty strings.
API Authentication
Use Domma CMS as a headless CMS by authenticating programmatically and including the access token with every request.
Login and obtain tokens
POST /api/auth/login
Content-Type: application/json
{
"email": "admin@example.com",
"password": "your-password"
}
// Response
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
Use the access token in subsequent requests
GET /api/collections/posts/entries
Authorization: Bearer {accessToken}
Refresh the access token
POST /api/auth/refresh
Cookie: refreshToken={token}
// Response
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}