Installation Guide
How to stand up a working Headless Auth Platform instance. Two paths are covered: a local
developer setup (fastest) and a Docker Compose stack (closest to self-hosted
production). The application lives in the target/ directory of the repository.
Commands are run from inside
target/unless stated otherwise. For a gentler first-run walkthrough see Getting started.
Prerequisites
- Docker with Docker Compose (for PostgreSQL 16 + Redis 7).
- uv — the Python package manager (install) — for the local developer path.
- A terminal and a clone of the repository.
Configuration
All configuration is via environment variables with the HAP_ prefix. Copy the template and
fill in the two values that have no safe default:
cd target
cp .env.example .env| Variable | Required | Purpose |
|---|---|---|
HAP_DATABASE_URL | yes | PostgreSQL connection (async driver). |
HAP_REDIS_URL | yes | Redis connection. |
HAP_MASTER_ENCRYPTION_KEY | yes | Base64 32-byte key for at-rest encryption. Generate below. |
HAP_ADMIN_API_KEY | yes (for admin APIs) | Bootstrap key for tenant/app provisioning. |
HAP_ISSUER_BASE_URL | recommended | Public base URL; per-tenant issuer is …/t/{slug}. |
HAP_KEY_PROVIDER | optional | env (default; encrypted PEMs on local disk) or db (encrypted PEMs in Postgres). See "Signing keys" below. |
HAP_DEFAULT_JWKS_ALGORITHM | optional | RS256 (default), ES256, or EdDSA. |
HAP_EMAIL_MODE | optional | console (default; logs the code) or smtp (send real email). See "Email / OTP delivery" below. |
HAP_EMAIL_FROM | for smtp | Sender address; must be a verified identity on your mail provider. |
HAP_SMTP_HOST / HAP_SMTP_PORT | for smtp | SMTP server (e.g. email-smtp.<region>.amazonaws.com / 587). |
HAP_SMTP_USERNAME / HAP_SMTP_PASSWORD | for smtp | SMTP credentials (secret). |
HAP_SMTP_STARTTLS / HAP_SMTP_SSL | optional | true/false; default STARTTLS on 587. |
Signing keys (HAP_KEY_PROVIDER)
Each tenant gets its own signing key, stored encrypted (AES-GCM with HAP_MASTER_ENCRYPTION_KEY)
— never in plaintext, never committed.
env(default) — keeps the encrypted key on the local filesystem (HAP_KEYSTORE_DIR). Fine for a developer machine with a persistent disk.db— keeps the encrypted key in Postgres. Use this for any deployment on ephemeral/ stateless containers (e.g. Kubernetes): a filesystem keystore is wiped on pod restart, which loses tenants' signing keys. The master key stays separate (a secret, never in the DB), so a database compromise alone yields no usable key material.
Email / OTP delivery (HAP_EMAIL_MODE)
Passwordless login and magic links email a one-time code.
console(default) — the code is logged to stdout, not emailed. Dev only; real users receive nothing.smtp— sends real email via any SMTP relay, including Amazon SES (setHAP_SMTP_HOSTto the SES SMTP endpoint and use SES SMTP credentials). TheHAP_EMAIL_FROMidentity must be verified with the provider, and (for SES) the account must be out of the sandbox to email arbitrary recipients. Delivery is best-effort and never blocks a login response.
Generate a master key:
python -c "import os,base64;print(base64.b64encode(os.urandom(32)).decode())"Put the result in HAP_MASTER_ENCRYPTION_KEY, and set HAP_ADMIN_API_KEY to a strong
random string.
Path A — Local developer setup
cd target
uv sync --extra dev # install dependencies
docker compose up -d postgres redis # start the datastores
uv run alembic upgrade head # create the database schema
uv run uvicorn hap.main:app --reload # start the service on :8000Verify it's healthy (second terminal):
curl -s localhost:8000/healthz # {"status":"ok"}
curl -s localhost:8000/readyz # database + redis both "ok"If /readyz reports ok for both database and redis, the instance is running.
Path B — Full Docker Compose stack (self-host style)
This builds the application image and runs it alongside PostgreSQL and Redis. The app container applies database migrations on startup.
cd target
# ensure .env has HAP_MASTER_ENCRYPTION_KEY and HAP_ADMIN_API_KEY set
docker compose up --build # app + postgres + redis (+ worker profiles)Then, from your host:
curl -s localhost:8000/readyz # expect status "ok"The Compose file also defines Celery worker/beat services (under a workers profile) for
background jobs.
Path C — Published image with the plain Docker CLI
Prefer to pull a prebuilt image and wire up the containers yourself (no Compose, no source
checkout)? Follow Local login guidelines, a step-by-step
Docker-CLI quickstart for tooltwist/wbsp-hap that stands up Postgres + Redis + HAP and configures
a tenant and application so locally-run apps can authenticate. The app image applies migrations on
startup, same as Path B.
First-run: create a tenant
The platform ships with no tenants. Create one (and confirm discovery resolves):
curl -s -X POST localhost:8000/v1/tenants \
-H "X-Admin-Key: <HAP_ADMIN_API_KEY>" -H "Content-Type: application/json" \
-d '{"name":"Demo","slug":"demo","password_policy":{"min_length":8}}'
curl -s localhost:8000/t/demo/.well-known/openid-configuration # JSON config = successYou now have a working instance. To connect an application, continue with the HAP integration guide.
Operating notes
- Database/cache: PostgreSQL 16 and Redis 7 are required; SQLite is not supported.
- Migrations: schema changes are applied with
uv run alembic upgrade headand can be reversed withuv run alembic downgrade base. - Signing keys: keys are generated per tenant and stored encrypted. The
envprovider keeps them on local disk (fine for a dev box); for any stateless/containerised deployment useHAP_KEY_PROVIDER=dbso keys survive restarts (see "Signing keys" under Configuration). - Health checks: wire
/healthz(liveness) and/readyz(readiness) into your orchestrator. - Managed option: prefer not to operate it yourself? A managed offering is available — contact us.
Troubleshooting
/readyzshowsdatabase: error→ confirmHAP_DATABASE_URLand that the Postgres container is healthy (docker compose ps).- Startup error about the master key → ensure
HAP_MASTER_ENCRYPTION_KEYis set to a base64-encoded 32-byte value. - Admin calls return 401 → check the
X-Admin-Keyheader matchesHAP_ADMIN_API_KEY.
See also
- HAP integration guide · Technical overview ·
Getting Started ·
Run HAP locally with the Docker CLI · developer quickstart:
specs/001-headless-auth-platform/quickstart.md