Skip to content

Architecture and domain boundaries

Sources of truth

OwnerOwns
ZITADELAuthentication identities, credential material, verification, MFA/passkeys, OIDC tokens, authentication sessions
Central Auth GatewayStable sub → local user mapping, canonical cross-platform profile, platform membership, linked accounts, dynamic onboarding values, soft deletion, legacy mappings, audit records, auth transactions, gateway sessions, handoffs
Platform BFFPlatform-local session after handoff exchange, final returnTo redirect, optional platform-hosted onboarding UI

Email is mutable metadata, never an identity key. users.zitadel_subject is unique. JIT provisioning upserts the user and creates a transactional profile shell.

System shape

There is one ZITADEL OIDC application for the Central Gateway. Its only registered redirect URI is AUTH_CALLBACK_URL (default http://localhost:8080/v1/auth/callback). Platforms are rows in the platforms table, not ZITADEL apps.

Request processing (authenticated APIs)

  1. JOSE verifies a ZITADEL access token against cached remote JWKS, issuer, audience, algorithm, expiry, and token type — or an opaque gateway session is read from the configured HttpOnly cookie.
  2. User endpoints provision/load the local user from sub (Bearer) or from the gateway session’s userId (cookie) and reject inactive accounts.
  3. Route handlers validate strict payloads and delegate to domain services.
  4. Services perform authorization-sensitive and multi-table changes transactionally.
  5. Fastify emits structured JSON logs with authorization and credential fields redacted.

User APIs (profile, account, onboarding values) accept either:

  • Authorization: Bearer <ZITADEL access token>, or
  • the gateway session cookie (AUTH_SESSION_COOKIE_NAME, default iesf_auth_session)

Cookie-authenticated writes require an Origin header that is listed in CORS_ORIGINS. Platforms that call Central with the exchanged gatewayToken must forward it as that cookie; the gateway does not accept the opaque token as a Bearer credential.

Central login and handoff boundary

Authentication is never ZITADEL callback → platform returnTo. Platforms redirect browsers to the public Central Gateway start endpoint. The gateway validates the active platform, server-registered onboarding policy, and allowlisted return URL, then persists random state, nonce, and an S256 PKCE verifier. State and nonce are stored as hashes; recovery values are AES-256-GCM encrypted with AUTH_TRANSACTION_SECRET.

After ZITADEL returns to the central callback, the gateway:

  1. Atomically consumes state
  2. Exchanges the authorization code with the stored PKCE verifier
  3. Validates the signed ID token and nonce, and verifies the access token
  4. JIT-provisions the local user and upserts platform membership
  5. Evaluates the current requirement version
  6. Creates a short-lived HttpOnly gateway session
  7. Either redirects to Account Center (incomplete central onboarding) or issues a one-time handoff_ code to the platform’s registered callback_url

The platform BFF authenticates to Central with its own Basic credential, consumes the handoff once, and builds a local session. No ZITADEL token crosses that boundary.

Dynamic onboarding (gateway-owned)

onboarding_field_definitions stores PROFILE_FIELD references and CUSTOM_FIELD definitions. Canonical profile values stay in typed columns; custom values use JSONB. Schema create/update/archive increments platforms.requirement_version and moves existing COMPLETE memberships to IN_PROGRESS. Completion is always recalculated server-side; client flags such as completed=true are ignored.

Reliability

  • Application instances keep no process-local session state and scale horizontally.
  • Auth transactions, gateway sessions, and handoffs live in PostgreSQL.
  • Migrations serialize with a PostgreSQL advisory lock.
  • /health/live has no dependency checks; /health/ready checks PostgreSQL.
  • SIGTERM stops accepting work and drains in-flight requests.
  • Avatar uploads use presigned PUTs directly between client and S3-compatible storage.