Production checklist
Walk through this list before flipping the auth backend to production.
Secrets
-
IDENTSPHERE_JWT_SECRETis at least 32 bytes from a CSPRNG (openssl rand -hex 32). -
IDENTSPHERE_JWT_SECRETis distinct from every other environment (dev, staging, per-customer). -
IDENTSPHERE_JWT_SECRETis sourced from a secrets manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault), NOT a checked-in file. - OAuth client secrets are likewise stored in a secrets manager.
- Database connection strings include
sslmode=require(or stricter).
Cookies + transport
-
IDENTSPHERE_COOKIES_SECURE=true. - The auth backend is fronted by HTTPS — TLS terminates at the load balancer / ingress / CDN.
-
IDENTSPHERE_PUBLIC_BASE_URLis the canonical HTTPS URL (https://auth.example.com, nothttp://, not the load-balancer's DNS name).
Database
- Postgres 14 or newer.
-
IDENTSPHERE_SCHEMAis pre-created (CREATE SCHEMA identsphere;). -
identsphere migrate uphas been run. - Database backups are configured AND verified via restore.
- Audit log retention policy is documented (
DELETE FROM IdentSphere.audit_logs WHERE created_at < ...) and scheduled.
Email
- A real
EmailSenderimplementation is wired up (NOTLogOnlySender). -
IDENTSPHERE_FROM_EMAILis a verified address on a domain you control. - Reverse DNS / SPF / DKIM / DMARC are configured for the sending domain.
- You've sent a test password-reset to a real inbox and verified it arrives.
WebAuthn / passkeys
-
IDENTSPHERE_RP_IDmatchesIDENTSPHERE_PUBLIC_BASE_URL's host (no scheme, no port). -
IDENTSPHERE_RP_ORIGINmatches the full URL including scheme. - You've enrolled one passkey and signed in with it from a clean browser to verify the configuration.
OAuth
- Google: redirect URI
{public_base_url}/v1/auth/oauth/google/callbackis registered in the Google Cloud console. - GitHub: same callback URL is registered in the GitHub OAuth App settings.
- You've completed a successful round-trip through each configured provider.
CORS
- If the auth backend and frontend are on different origins, CORS is
configured explicitly (no
Access-Control-Allow-Origin: *). -
Access-Control-Allow-Credentials: true. - The frontend uses
credentials: 'include'(oraxioswithCredentials).
Rate limiting
-
POST /v1/auth/loginis rate-limited (mounttower-governoror use your edge's rate limiter — Cloudflare, nginxlimit_req, etc.). -
POST /v1/auth/password/forgotis rate-limited. -
POST /v1/auth/email-otp/requestis rate-limited. -
POST /v1/auth/registeris rate-limited (defends against signup spam).
Avatar uploads
- Object storage is configured (S3 / R2 / GCS / MinIO), NOT
LocalFsStorage. - The 5 MiB body-size limit is preserved (don't lift it on the ingress / nginx).
- CDN / cache strategy for
avatar_urlis decided.
Observability
- Structured logs (
tracing) flowing to a central log store. - Health-check endpoint wired into the orchestrator (Kubernetes, Fargate, etc.).
- At minimum these metrics are alerted on:
- p95 latency on
/v1/auth/login - 5xx rate on any endpoint
- 401 rate on
/v1/auth/login(credential-stuffing signal) - 429 rate on
/v1/auth/mfa/challenge
- p95 latency on
- Audit-log queries are wired into your SIEM.
Operational
-
identsphere migrate upis in the deploy pipeline BEFORE the new app version goes live. - Rolling deploys verified — zero-downtime restarts.
- Multiple replicas for HA. (Stateless service; share DB.)
- Redis (or other shared cache) configured for
session_cacheif you're running > 1 replica AND care about cache consistency. - Runbook documented for
IDENTSPHERE_JWT_SECRETrotation (knows that every session will be forced to sign out).
Compliance + legal
- Privacy policy reflects the data the SDK stores (email, password hash, MFA secret, audit log).
- Cookie consent banner if your jurisdiction requires one — the SDK's session cookies are functional / strictly necessary in most frameworks but verify with counsel.
- Data-deletion process documented and tested ("right to be forgotten") — see Data export.
Smoke tests
After deploying, run these against the production endpoint:
# Registration round-trip
curl -X POST https://auth.example.com/v1/auth/register \
-H 'Content-Type: application/json' \
-d '{"email":"smoke@example.com","password":"smoke-test-password","organization_name":"Smoke"}' \
-c /tmp/c.txt
# Session check
curl https://auth.example.com/v1/auth/session -b /tmp/c.txt
# Logout
curl -X POST https://auth.example.com/v1/auth/logout -b /tmp/c.txt -c /tmp/c.txt
# Confirm logout
curl -i https://auth.example.com/v1/auth/session -b /tmp/c.txt # expect 401
All four should hit the success path. If they don't, fix before letting real users in.