Useful Commands
A practical command reference for application developers working on (or deploying) the Headless Auth Platform. It assumes you have checked out this repository and have a terminal open at its root.
Who this is for. This page is for people building and shipping this application. It does not cover standing up the WBSP platform itself (that is the platform operator's job). Where a command talks to the platform, it uses the
wbsp-appCLI, which your platform team provides.Where things live. All application code is under
target/. Run the Python/dev commands below from insidetarget/. The deployment manifests (wbsp.yaml,wbsp.Docker) live at the repository root.
1. Local development (run the app on your machine)
Everything here runs from the target/ directory and uses uv
(a fast Python package manager). The app needs a PostgreSQL and a Redis to talk to — the
quickest way to get both is Docker Compose (see §3).
cd target
# Install dependencies (including dev tools) into a local .venv
uv sync --extra dev
# Copy the example environment file and adjust as needed (never commit a real .env)
cp .env.example .env
# Apply database migrations, then start the API with hot reload on http://localhost:8000
uv run alembic upgrade head
uv run uvicorn hap.main:app --reload --port 8000
# Quick health checks (in another terminal)
curl -s localhost:8000/healthz # liveness → {"status":"ok"}
curl -s localhost:8000/readyz # readiness → checks the DB and RedisThe server emits structured JSON logs to stdout (one line per event, mapped to the
OpenTelemetry Logs Data Model). To read them comfortably while developing, pipe through a
JSON pretty-printer, e.g. uv run uvicorn hap.main:app --reload | jq.
Configuration (environment variables)
The app is configured entirely from the environment (12-factor). Locally these come from
target/.env; see .env.example for the full list. The most
important ones:
| Variable | Purpose |
|---|---|
HAP_DATABASE_URL | SQLAlchemy/asyncpg URL for Postgres |
HAP_REDIS_URL | Redis URL (rate limits, OTP/challenge state, JWKS cache) |
HAP_MASTER_ENCRYPTION_KEY | base64 32-byte key for at-rest encryption (secret) |
HAP_ADMIN_API_KEY | bootstrap admin key for the management API (secret) |
HAP_ISSUER_BASE_URL | public issuer base URL used in tokens/discovery |
HAP_ENVIRONMENT | dev | staging | prod |
On the WBSP platform you do not set
HAP_DATABASE_URL/HAP_REDIS_URLdirectly. When you enable the platform datastores inwbsp.yaml(§5), the platform injectsDATABASE_HOST/_PORT/_NAME/_USER/_PASSWORD/_SSLandREDIS_HOST/_PORT(+REDIS_NAMESPACE); the app builds the connection URLs — and applies the Redis key prefix — automatically.
2. Tests and quality gates
These are the same checks CI runs; all must pass before merge. Run from target/.
# Full test suite — unit + integration. Spins up real ephemeral Postgres & Redis via
# testcontainers (Docker must be running), so no manual DB setup is needed.
uv run pytest
# Style: lint + format check
uv run ruff check .
uv run ruff format --check .
# Static types (strict)
uv run mypy --strict src/hap
# Migrations apply cleanly up and back down
uv run alembic upgrade head && uv run alembic downgrade base
# Regenerate the published OpenAPI document from the code
uv run python scripts/export_openapi.pySmoke-test a running server end to end
scripts/demo_flow.py drives the whole OAuth2/OIDC journey against a live server
(provision tenant → register app → register + log in a user → PKCE authorize → token
exchange → userinfo) and exits non-zero if any step fails — handy as a post-deploy check.
Start a server first (see §1), then:
uv run python scripts/demo_flow.py # against http://localhost:8000
HAP_DEMO_BASE_URL=https://auth.wbsp.ai \
HAP_ADMIN_API_KEY=… uv run python scripts/demo_flow.py # against a deployed instanceMigrations:
uv run alembic revision --autogenerate -m "describe the change" # create a migration
uv run alembic upgrade head # apply
uv run alembic downgrade -1 # roll back one step3. Local containers (Docker Compose)
target/docker-compose.yml brings up Postgres, Redis, and
the app together — the closest local mirror of a real deployment. Run from target/.
docker compose up --build # build the image and start postgres + redis + app
docker compose up -d postgres redis # just the datastores (then run the app via uv, §1)
docker compose ps # what's running
docker compose logs -f app # follow the app's logs
docker compose down # stop everything
docker compose down -v # stop and delete the data volumes (fresh start)
# Open a psql shell inside the database container
docker compose exec postgres psql -U hap -d hap4. Deploying on WBSP (wbsp-app)
Deploys are driven by the root wbsp.yaml, which points at
wbsp.Docker for the build and enables a platform-managed Postgres + Redis
(database.enabled / redis.enabled). The container listens on port 8080 (the platform's
ingress contract). A deploy selects a placement with --destination <name> (reading the
matching .env.<destination>); the lifecycle commands (list/status/logs/stop/remove)
scope by --provider / --tenant instead. This project declares these destinations: local
(type: dev), and wbsp / stage / twist / aws (type: aws).
# Deploy / redeploy to a placement (the destination's type selects where it lands)
wbsp-app deploy --config wbsp.yaml --destination aws # EKS (aws)
wbsp-app deploy --config wbsp.yaml --destination wbsp # EKS (aws), wbsp enclave/tenant
# List apps and check status / health (list scopes by --provider; aws status needs --tenant)
wbsp-app list --provider aws
wbsp-app list --provider aws --health
wbsp-app status headless-auth --tenant test
# Stream logs (structured JSON; the platform's LogWatch also ingests these)
wbsp-app logs headless-auth --tenant test --follow
wbsp-app logs headless-auth --tenant test --lines 500
# Stop (keep the database + Redis) / remove (tear down and DELETE the data)
wbsp-app stop headless-auth --tenant test
wbsp-app remove headless-auth --tenant testFor the local inner loop, use the local (type: dev) destination: the deploy brings up
Postgres/Redis in containers and writes a .env beside the app; you then run HAP yourself from
your IDE (there is no wbsp-app dev command in the v2 CLI):
wbsp-app deploy --config wbsp.yaml --destination local # brings up DB/Redis, writes .env
source .env && uv run uvicorn hap.main:app --reload # run HAP yourself (from target/)
wbsp-app stop headless-auth --tenant test # stop the data services (keeps data)Verify the image runs before an aws deploy:
docker build -f wbsp.Docker -t headless-auth:dev .thendocker run -p 8080:8080 --env-file target/.env headless-auth:dev, and openhttp://localhost:8080/healthz.
5. Backing services: Postgres and Redis
Both datastores this app needs are first-class platform resources — you just enable them
in wbsp.yaml and the platform provisions and injects them:
database:
enabled: true # platform-managed PostgreSQL (RDS); injects DATABASE_*
redis:
enabled: true # platform-managed Redis; injects REDIS_* + REDIS_NAMESPACE
durable: false # true → a persistent store rather than a cacheYou do not stand these up yourself or wire them through a Parallel Namespace. On deploy
the platform injects DATABASE_* and REDIS_* (including REDIS_NAMESPACE, the key prefix
this app must stay within); hap.config builds the connection URLs and hap.core.redis
applies the key prefix automatically, so nothing is hard-coded.
Parallel Namespaces are for other backing services — e.g. Forgejo, ClickHouse — not Postgres/Redis. If you ever need one of those, define a
wbsp-services.yamland runwbsp-app services up --config wbsp-services.yaml; see the platform'sparallel-services-guide.md.
6. Accessing the database on-platform
Day-to-day, prefer the application's own admin API and migrations over hand-editing data.
When you genuinely need a shell against the platform database (e.g. to inspect a
production issue), follow the platform's accessing-the-database.md — it explains how to
obtain credentials and tunnel in. The platform sets DATABASE_SSL=true on managed (RDS)
databases; the app enables TLS automatically when it sees that.
Quick reference
| I want to… | Command |
|---|---|
| Run the app locally | uv run uvicorn hap.main:app --reload (from target/) |
| Run all tests | uv run pytest |
| Smoke-test a running server | uv run python scripts/demo_flow.py |
| Lint + types | uv run ruff check . && uv run mypy --strict src/hap |
| New migration | uv run alembic revision --autogenerate -m "..." |
| Regenerate OpenAPI | uv run python scripts/export_openapi.py |
| Everything in containers | docker compose up --build (from target/) |
| Deploy to the cloud | wbsp-app deploy --config wbsp.yaml --destination aws |
| Tail deployed logs | wbsp-app logs headless-auth --tenant test --follow |
| Enable Postgres + Redis | set database.enabled / redis.enabled in wbsp.yaml |