Skip to content

ADR 16: Auth Scope — Local JWT Users and API Tokens

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:

  1. OIDC (Auth0 or any compatible) for browser-based human users
  2. SAML for enterprise identity providers
  3. 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/login returns a JWT (HS256, 24-hour TTL)
  • JWT stored in HttpOnly cookie for WebUI; Authorization: Bearer header 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-tokens endpoint
  • 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_PASSWORD env var creates initial admin user on startup
  • If not set, binary logs a curl command 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:

  1. OIDC can be added as an alternative login flow — the auth.Authenticator interface (not yet extracted) would have JWT and OIDC implementations. Existing JWT users remain valid.
  2. API tokens remain the service-account mechanism — they're already not tied to PGP.
  3. PGP would be added only if air-gapped CLI authentication is required (unlikely for personal cloud).

See Also

  • ADR 15 — Frontend stack decision
  • ADR 17 — Dropped features list