Multi-user roles
Mezzanine ships with full multi-user auth out of the box. No public-mode escape hatch — every install requires creating a first admin.
The four roles
| Role | Can do |
|---|---|
viewer | Read-only. See servers, deploys, runs, metrics. Cannot trigger anything. |
moderator | Everything viewer does plus trigger workflows, approve approval-gate steps. |
admin | Everything moderator does plus add/edit/delete servers, workflows, pools, integrations. |
owner | Everything admin does plus manage other users (create, change role, delete), rotate panel-wide secrets. |
The very first user created via the setup wizard becomes owner.
How enforcement works
Two layers — both apply on every request:
- Backend route-level —
roleGatemiddleware inbackend/src/middleware/auth.tsmatches the request method + path against a per-resource allowlist. Returns403 INSUFFICIENT_ROLEif the user’s role doesn’t meet the minimum. - Frontend UI gating —
<Gated min="admin">wraps buttons/forms so users without the role don’t see the affordance at all. (Defense in depth — the backend gate is the real protection; the UI gate is a UX nicety.)
Both layers stay in sync because they read from the same shared ROLE_RANK table.
Sessions
- HTTP-only
cp_sessioncookie, 30-day default lifetime, sliding renewal - Token = 256-bit random, stored in
admin_sessionstable - Logout deletes the row (server-side revocation works immediately)
- Optional TOTP — enable in your user profile, use any TOTP app (1Password, Authy, Google Authenticator)
Password storage
- bcrypt hashed with a per-install cost factor (default 12)
- Never logged, never sent over the wire after the initial create / change
- Password change requires the current password (no admin-can-set-anyone’s-password backdoor by default)
Adding users
owner only: Settings → Users → New user → username, email (optional), role, initial password. The user changes their password on first login.
Adding a moderator for self-deploy
Common pattern: create a moderator named ci or webhooks. Webhook deliveries use the workflow’s HMAC secret (no role check) but manual triggers + approvals in the UI need a logged-in user with at least moderator. So a dedicated low-privilege account for “things that should run but not configure” keeps your audit log clean.
What’s NOT included (yet)
- SSO / SAML / OIDC — local accounts only. SAML is on the roadmap when there’s enterprise demand.
- Per-server permissions — roles are global. A
moderatorcan deploy any workflow, not “deploys for servers tagged staging only.” Worth doing if you have a team but the global role is usually enough. - Audit log UI — the
activitiestable records everything but the UI to browse it is minimal. Improvement: add a richer audit view.