Auth configuration — environment variables (Headless Auth Platform)
This project is the identity provider (HAP). Its env vars configure the server itself — its
database, signing keys, issuer identity, admin access, and email delivery. The relying-party apps
(website, CRM) do not appear here as config; instead, each app is stored as an application row
(client_id + hashed secret + redirect URIs) and each wbsp-style tenant as a tenant row, created
via the admin API or the seed script — not via env vars.
All variables use the HAP_ prefix (pydantic-settings env_prefix). For a local source run
(uv run uvicorn …) the values live in target/.env. For a platform deploy, non-secret
per-environment values are set in wbsp.yaml under destination.<name>.env:, and secrets are
declared by reference in wbsp.yaml secrets: with their values in the git-ignored
.env.<destination> beside the manifest — each destination reads only its own file
(destinations never layer). See also aws-rollout.md.
Variables
| Variable | What it is | Where to get the value |
|---|---|---|
HAP_DATABASE_URL | PostgreSQL connection (SQLAlchemy async). | Local: docker-compose Postgres (…@localhost:54390/hap). AWS: the platform injects DATABASE_* and derives this automatically — don't set it. |
HAP_REDIS_URL | Redis connection (rate limits, OTP/challenge state, JWKS cache). | Local: docker-compose Redis. AWS: injected as REDIS_* and derived automatically. |
HAP_ISSUER_BASE_URL | The public base URL of this platform; tenants' OIDC issuer is {this}/t/{tenant}. Used in iss/aud, discovery, and (this matters) deciding whether the hosted-session cookie is Secure (https ⇒ Secure). | Chosen per environment: local http://localhost:8000; AWS https://auth.wbsp-demo.com. Set in wbsp.yaml per destination (destination.<name>.env). |
HAP_ADMIN_API_KEY | Master admin key for the admin API (/v1/tenants, /v1/applications, /v1/webhooks, …). | You generate it (openssl rand -base64 32), declare it by reference in wbsp.yaml secrets:, and put the value in the git-ignored .env.<destination>. It becomes the admin key on next deploy. |
HAP_MASTER_ENCRYPTION_KEY | AES key that envelope-encrypts the tenant signing keys stored in the DB (key_provider=db). | Generate once (openssl rand -base64 32) and never change it — a new value makes existing signing keys undecryptable and breaks all token signing. Recover the existing one when redeploying. |
HAP_KEY_PROVIDER | Where signing keys live: env | db | aws_kms | vault. | Local default env; AWS uses db (set in wbsp.yaml). |
HAP_ENVIRONMENT | dev | staging | prod (affects logging/behaviour). | Set per destination in wbsp.yaml. |
HAP_EMAIL_MODE | console (logs OTP codes to stdout — local) or smtp (real email). | Local console; AWS smtp. |
HAP_EMAIL_FROM | From-address for OTP/magic-link email (must be SES-verified on AWS). | Your verified sender, e.g. no-reply@wbsp.ai. |
HAP_SMTP_HOST / _PORT / _USERNAME / _PASSWORD / _STARTTLS / _SSL | SMTP relay for email_mode=smtp. | AWS SES SMTP endpoint + credentials (SES console → SMTP settings). On the platform these are declared by reference in wbsp.yaml secrets:, with values in each cloud destination's git-ignored .env.<destination> (keys SES_SMTP_USERNAME/SES_SMTP_PASSWORD). |
HAP_WEBAUTHN_RP_ID / _RP_NAME / _ORIGIN | Passkey (WebAuthn) relying-party identity. | Bind to the platform's own domain per destination (localhost / auth.wbsp-demo.com). |
Per-tenant settings are NOT env vars — they are columns on the tenants row, toggled via the
admin API: hosted_login_enabled, passwordless_jit_provisioning (PATCH /v1/tenants/{id}).
Applications (the website/CRM clients) are application rows created via POST /v1/applications
(or target/scripts/seed_hosted_login.py): client_id, client_secret (returned once, stored
hashed), redirect_uris, post_logout_redirect_uris, scopes.
Equivalent names across the three projects
Same concept, different variable name in each project (because each uses a different framework/convention):
| Concept | Platform (this repo, FastAPI) | Website (Next.js, custom OIDC) | CRM (Next.js, Auth.js) |
|---|---|---|---|
| Platform base URL / issuer | HAP_ISSUER_BASE_URL | HAP_BASE_URL + HAP_TENANT | AUTH_HAP_ISSUER (= {base}/t/{tenant}) |
| Tenant | tenants row (slug wbsp) | HAP_TENANT (+ HAP_TENANT_ID) | encoded in AUTH_HAP_ISSUER path |
| App client_id | application.client_id | HAP_WEBSITE_CLIENT_ID | AUTH_HAP_ID |
| App client secret | application.client_secret_hash (hashed) | HAP_WEBSITE_CLIENT_SECRET | AUTH_HAP_SECRET |
| Redirect / callback URI | application.redirect_uris | HAP_WEBSITE_REDIRECT_URI | derived {AUTH_URL}/api/auth/callback/hap |
| Post-logout URI | application.post_logout_redirect_uris | HAP_WEBSITE_POST_LOGOUT_REDIRECT_URI | derived {NEXT_PUBLIC_APP_URL}/login |
| "Login via platform" toggle | tenant.hosted_login_enabled | HAP_AUTH_ENABLED | NEXT_PUBLIC_HAP_ENABLED (+ AUTH_HAP_ISSUER present) |
| This app's own public URL | HAP_ISSUER_BASE_URL | APP_BASE_URL | AUTH_URL (+ AUTH_TRUST_HOST) / NEXT_PUBLIC_APP_URL |
| Local session signing secret | n/a (issues tenant-signed tokens) | AUTH_SECRET | AUTH_SECRET |
| Admin API key | HAP_ADMIN_API_KEY | HAP_ADMIN_KEY (access-control calls) | n/a |
| Webhook signing secret | webhook.signing_secret | HAP_WEBHOOK_SECRET | n/a |
| In-cluster service host (AWS) | n/a | HEADLESS_AUTH_AUTH_HOST/_PORT (injected) | HEADLESS_AUTH_AUTH_HOST/_PORT (injected) |
| At-rest encryption key | HAP_MASTER_ENCRYPTION_KEY (signing keys) | n/a | ENCRYPTION_KEY (stored OAuth tokens) |