Files
sbbb/docs/identity.md
Sienna Meridian Satterwhite 97e87c6dda docs: add identity & auth documentation — The Guest List 💋
OIDC auth flow, Kratos + Hydra, client registry (12 apps), session
management, identity schemas, self-service flows, Vault integration.
2026-03-24 11:46:28 +00:00

5.7 KiB

The Guest List 💋

Every app in The Super Boujee Business Box authenticates through the same door. One login, every room. You don't re-authenticate because you walked from Docs to Drive — that's not a feature, that's just manners.

The identity layer is built on Ory Kratos (who you are) and Ory Hydra (what you're allowed to do). Lightweight Go binaries, no JVM, no XML — they fit k3s like they were born for it. We chose them over Keycloak because we wanted something that didn't need 2GB of RAM to tell you who's logged in.


The Auth Flow

You → any app (docs.sunbeam.pt, drive.sunbeam.pt, etc.)
  → 302 redirect to auth.sunbeam.pt
  → Hydra says "who are you?"
  → Kratos login UI (password, TOTP, WebAuthn — your pick)
  → authenticate
  → Hydra issues OIDC token
  → 302 back to the app
  → app validates via mozilla-django-oidc
  → session established ✨

That's it. Every La Suite app uses the same mozilla-django-oidc library. Swapping from Keycloak (the French government default) to Hydra was transparent at the app level — same OIDC, different provider.


The Players

Ory Kratos — Identity Management

Handles the "who are you" part:

  • Registration — create accounts (or provision them via sunbeam auth identity create)
  • Login — password, TOTP, WebAuthn, lookup secrets
  • Profile — name, email, metadata
  • Recovery — password reset via email (through Postfix)
  • Session — 720 hours (30 days), cookie-scoped to parent domain

The cookie-scoping is key: setting the session cookie on the parent domain means all *.sunbeam.pt subdomains share the session. Log in once, you're everywhere.

Identity Schemas

Three schemas for different types of users:

Schema Purpose
employee Core team (Sienna, Amber, Lonni) — full access, all apps
default Standard users — for when the team grows
external External collaborators — limited scope

Ory Hydra — OAuth2 / OIDC Provider

Handles the "what can you do" part:

  • Issues OAuth2 access tokens and OIDC ID tokens
  • Manages the OIDC client registry
  • Token lifetimes: access/ID tokens 1h, refresh tokens 720h, auth session 720h
  • OpenID Connect discovery at auth.sunbeam.pt/.well-known/openid-configuration

Hydra Maester

The secret sauce for client management. Watches HydraOAuth2Client CRDs in Kubernetes and automatically:

  1. Registers the client with Hydra
  2. Creates a K8s Secret with CLIENT_ID and CLIENT_SECRET
  3. Keeps them in sync if the CRD changes

No manual client registration. Declare a CRD, get a working OIDC client.


The OIDC Client Registry

Every app is a registered OIDC client. Hydra Maester manages all of them:

App Secret Name Redirect URI Notes
Docs oidc-docs docs.DOMAIN/api/v1.0/callback/
Drive oidc-drive drive.DOMAIN/api/v1.0/callback/
Meet oidc-meet meet.DOMAIN/api/v1.0/callback/
Messages oidc-messages mail.DOMAIN/api/v1.0/callback/ offline_access scope
People oidc-people people.DOMAIN/api/v1.0/callback/
Find oidc-find find.DOMAIN/oidc/callback/
Gitea oidc-gitea src.DOMAIN/user/oauth2/Sunbeam/callback
Calendars oidc-calendars cal.DOMAIN/api/v1.0/callback/
Projects oidc-projects projects.DOMAIN/oidc-callback
Hive oidc-hive (none) client_credentials grant
Tuwunel oidc-tuwunel (matrix namespace) Matrix SSO
Grafana grafana-oidc (monitoring namespace) auto-assign Admin role

Messages gets offline_access to maintain sessions across browser restarts. Hive uses client_credentials because it's a service, not a human. Grafana auto-assigns Admin because if you're authenticated, you're on the team.


Self-Service Flows

Users can manage their own security:

Method What it is
Password Classic email + password
TOTP Time-based one-time passwords (Google Authenticator, etc.)
WebAuthn Hardware security keys (YubiKey, etc.)
Lookup Secrets Backup/recovery codes

Recovery emails go through Postfix (same SMTP used by Messages) at postfix.lasuite.svc:25.


Vault Integration

Secrets don't live in Git. They live in OpenBao (Vault) and sync to Kubernetes via Vault Secrets Operator.

OIDC Client Secrets

Hydra Maester creates K8s Secrets from HydraOAuth2Client CRDs. These contain CLIENT_ID and CLIENT_SECRET that apps consume.

Dynamic Database Credentials

Every app's database password rotates every 5 minutes via VaultDynamicSecret. The Vault Secrets Operator:

  1. Requests new credentials from OpenBao's database engine
  2. Creates/updates the K8s Secret
  3. Triggers a rollout restart of the affected Deployment

Static Secrets

Django secret keys, DKIM keys, API tokens — synced from OpenBao KV v2 with 30-second refresh via VaultStaticSecret.


Admin Access

For when you need to manage identities directly:

# Via sunbeam CLI
sunbeam auth identity list
sunbeam auth identity create amber@sunbeam.pt --name "Amber"
sunbeam auth identity get <id>

# Via Kratos Admin API (auth-gated through proxy)
# Accessible at id.sunbeam.pt (requires Hydra /userinfo auth)

# Via Hydra Admin API (auth-gated through proxy)
# Accessible at hydra.sunbeam.pt (requires Hydra /userinfo auth)

Sol☀️ also has Kratos admin access for identity operations within Matrix chat.


The Login UI

Sunbeam-branded login, consent, and recovery pages served by kratos-admin-ui. This is what you see at auth.sunbeam.pt — the velvet rope. Custom logo, custom colors, same energy as everything else in the box.