Guides / Production
Production deployment.
A release checklist for the API, customer BFF, shared reference state, browser controls, observability, and biometric assurance.
BFF topology
Terminate TLS at a trusted edge and expose the BFF on the application’s own origin. Keep its scoped, expiring Project service credential in a server secret manager. Mount one ComplicatedAuthServer handler beneath /auth or /api/auth.
Shared reference storage
Use RedisReferenceStore or a custom ReferenceStore with authoritative TTL and deletion. All BFF instances must share it. Configure Redis authentication, TLS, eviction monitoring, and a key namespace unique to the environment.
Browser controls
- Deploy a restrictive Content Security Policy and remove unsafe script sinks.
- Use HTTPS, HSTS, exact origins, and secure cookies.
- Do not persist browser session tokens beyond the intended tab lifecycle without an explicit risk decision.
- Keep request execution disabled in publicly hosted API documentation.
Give the management console and every customer WebAuthn application distinct RP IDs on stable hostnames. Ports do not distinguish RP IDs. Treat changing either hostname as a credential-domain migration, and verify that reverse proxies preserve the exact configured Origin without deriving security policy from forwarded host headers.
API and database
Run migrations before directing traffic, require readiness to pass, and retain enough database capacity for ceremony and audit writes. Startup serializes migrators with a PostgreSQL advisory lock and verifies the checksum of every applied migration. Treat a checksum or missing-history failure as a bad release artifact; restore the original file and ship a new migration instead of bypassing the check. Configure trusted proxies explicitly so rate limits and audit IPs cannot be spoofed.
Stable origins and cryptographic keys
OAUTH_ISSUERis the exact public API origin used in discovery and signed-tokeniss. Production requires HTTPS. Never infer it fromHostor forwarded headers.CONSOLE_ORIGINis the exact first-party browser origin for cookies, CSRF validation, authentication, and consent.INTERNAL_API_URLis only the console container’s runtime upstream. It must never appear in discovery, redirects, examples, or tokens.DATA_ENCRYPTION_KEYSis an orderedversion:base64url-keykeyring. The first entry encrypts new OAuth signing material; retained entries decrypt old ciphertext. Add the new key first, deploy, verify reads, then retire an old key only after no rows reference it and backups no longer require it.SECRET_HASH_KEYprotects stored credential and rate-limit digests. Manage it independently from data-encryption keys and do not rotate it without a credential migration plan.
The API serializes OAuth signing-key creation across replicas, publishes active and still-required retiring public keys in JWKS, and signs with RS256. Monitor key age, active-key count, JWKS cache behavior, signing failures, and ciphertext key-version usage. Changing the issuer is a security-domain migration, not a routine hostname change.
Management authentication
A password verification never creates a management session. Signup and invitation acceptance create bootstrap sessions that can only discover themselves, sign out, and enroll the first passkey or attested security key. Require strong assurance on every other control-plane handler. Exclude the one-time login-attempt client secret from edge logs, request tracing, browser telemetry, replay tooling, and support captures; it belongs only in memory and the dedicated child-operation header.
Password reset is the lost-authenticator recovery boundary. It revokes sessions and OAuth artifacts and removes every management WebAuthn credential, forcing fresh enrollment. Alert on recovery and credential removal, protect recovery mailboxes, and rehearse both a lost-device recovery and a suspected-mailbox-compromise response.
OAuth and delegated authorization
Publish discovery and JWKS through the same trusted edge as the configured issuer. Cache public metadata briefly, preserve retiring keys beyond the maximum token lifetime plus skew, and verify an unknown kid by refreshing the configured JWKS once. Access tokens expire after ten minutes by default. Online UserInfo and authorization decisions enforce database revocation immediately; separately hosted APIs validating JWTs offline cannot observe revocation before expiry.
Alert on client-secret creation and revocation, repeated invalid-client failures, authorization throttling, grant or scope changes, signing-key rotation, decision dependency failure, and denied sensitive operations. Never log request handles, codes, verifiers, client secrets, access tokens, ID tokens, callback query strings, or authorization headers.
Retry safety
Send an idempotency key only to operations that publish the header in OpenAPI. Reuse the same key and identical request for network retries; a changed request conflicts. Store the response before considering the operation complete, honor retry guidance while another attempt owns its lease, and do not assume that an unlisted mutation is safe to repeat.
Support data and retention
Support subjects, correspondence, diagnostics, attachment metadata and bytes, and external references are encrypted in PostgreSQL. Budget database storage and backup time for the 25 MiB per-case limit, scan or quarantine downloaded files before opening them in privileged tooling, and monitor rejected upload types and sizes. Closing a case schedules deletion after 365 days. Workers lease jobs across replicas, retry transient failures with a bound, dead-letter exhausted work, and re-check the locked case status and deadline before deleting anything.
Job queue and maintenance
Every API replica leases work with FOR UPDATE SKIP LOCKED. Size BACKGROUND_JOB_WORKERS, BACKGROUND_JOB_POLL_INTERVAL, and BACKGROUND_JOB_LEASE_DURATION for database capacity and dependency latency. The recurring maintenance job uses bounded deletes and covers expired transient authentication, OAuth, idempotency, rate-limit, invitation, email, session, and completed-job records.
Do not expose generic job endpoints to customers. Use jobctl list for payload-free inspection and jobctl replay only after recording an actor and incident-quality reason; every replay is transactionally written to immutable operator history. Back up the database before release, restore it into an isolated environment, verify migration checksums and keyring availability, and confirm maintenance does not delete live sessions or pending work.
Observability
Correlate requests using X-Request-ID. Alert on login throttling, failed FIDO verification, management recovery, authenticator removal, service-credential issuance and revocation, unexpected expiry, user disablement, session revocation, readiness failure, maintenance lag, Support Case backlog, failed or dead-lettered jobs, attachment rejection, and biometric-provider errors. Never log credentials, login-attempt client secrets, WebAuthn payloads, support content, attachment names or bytes, external identifiers, or selfie bytes.
Release gate
- OpenAPI lint, generated-code drift, SDK tests/typecheck/build, console E2E, and docs accessibility all pass.
- No known high or critical dependency advisories remain.
- The PostgreSQL acceptance suite runs against a disposable database.
- Discovery, JWKS, identity authorization, resource-bound authorization, consent, token exchange, UserInfo audience rejection, decisions, and revocation pass through the production topology.
- Credential rotation, rollback, recovery, and incident ownership are rehearsed.
- Biometric deployments document consent, retention, liveness, fallback, and provider deletion guarantees.