ADR 16: Auth Scope — Local JWT Users and API Tokens
Status: Accepted (2026-06-05)
Context
The reference platform (arch/04-features/authentication.md) specifies three authenticators:
- OIDC (Auth0 or any compatible) for browser-based human users
- SAML for enterprise identity providers
- PGP-signed requests for CLI and service accounts
For RezusCloud (personal cloud), the operator is the owner. There is no enterprise IdP. There are no external service accounts requiring cryptographic identity. The OIDC/SAML/PGP stack adds significant complexity (callback handling, key management, PGP key generation UI) for zero benefit at this scale.
Decision
Adopt local JWT users + API tokens as the only authentication mechanisms for v1:
Human users
- Username + password stored locally (bcrypt-hashed)
- Login endpoint
/api/v1/auth/loginreturns a JWT (HS256, 24-hour TTL) - JWT stored in HttpOnly cookie for WebUI;
Authorization: Bearerheader for CLI - Refresh not implemented — re-login after expiry
- Three roles:
admin(full access),edit(no user management),view(read-only)
API tokens (replace PGP service accounts)
- Random 32-byte hex strings, generated by
/api/v1/api-tokensendpoint - SHA-256 hashed in storage (same pattern as JoinToken in
internal/api/jointoken/) - Shown once at creation time — user must copy immediately
- Identified by a user-chosen name (e.g.
ci-deploy,homelab-automation) - Scoped to the creating user's role
- Revocable via DELETE endpoint
- Used as
Authorization: Bearer <token>against any/api/v1/*endpoint
First-run bootstrap
REZUSCLOUD_ADMIN_PASSWORDenv var creates initial admin user on startup- If not set, binary logs a
curlcommand to create the first admin via API - No interactive setup wizard, no EULA page
What we don't build (v1)
- No OIDC — no callback URLs, no external IdP configuration, no session synchronization
- No SAML — no XML security, no metadata exchange, no enterprise SSO
- No PGP — no key generation, no signed request verification, no key rotation UI
- No service accounts as a distinct identity type — API tokens scoped to a real user
- No password reset flow — admin can reset via CLI or API
- No MFA/2FA — single factor is acceptable for a personal cloud
RBAC model
Three roles map to Kubernetes ClusterRole naming convention:
| Role | Permissions |
|---|---|
admin |
All operations including user management and audit log access |
edit |
All operations on tenants/machines/nodegroups/patches/tokens within scope; no user management |
view |
All GET operations; no mutations |
Token authorization is enforced via internal/auth/middleware.go (already implemented). Audit middleware records the actor identity for every mutation (see ADR for audit logging).
Migration path
If multi-tenant or enterprise needs emerge:
- OIDC can be added as an alternative login flow — the
auth.Authenticatorinterface (not yet extracted) would have JWT and OIDC implementations. Existing JWT users remain valid. - API tokens remain the service-account mechanism — they're already not tied to PGP.
- PGP would be added only if air-gapped CLI authentication is required (unlikely for personal cloud).