keyward.broker console
control plane onlineonlinedev mode
Docs / Self-hosting

Run the broker yourself

The broker is a long-running Node service (Hono) with a Postgres pool — it wants an always-on container, not a serverless function. The dashboard is a Next.js app that talks to it over HTTPS; it never touches Postgres directly.

Topology

production shape
 agent SDK ─┐
            ├─▶  broker (container)  ──▶  Postgres (Neon)
 dashboard ─┘        ▲
 (Vercel)            └─ verifies human sessions + agent identity tokens (JWKS)

Container

terminal
docker build -t keyward-control-plane .
docker run -d --name keyward --restart=always -p 8787:8787 \
  -e DATABASE_URL='postgres://…' \
  -e KEYWARD_MASTER_KEY='<strong value>' \
  keyward-control-plane

Migrations apply at boot. Fly.io config ships in the repo (fly.toml); Railway/Render detect the Dockerfile with zero extra config. Health check: GET /healthz. Never bake secrets into the image — inject them at deploy time.

Environment reference

VariableRequiredWhat
DATABASE_URLPostgres. TLS + pooler handling auto-applied for *.neon.tech
KEYWARD_MASTER_KEYenvelope-encryption master key (wraps secrets + the signing key)
KEYWARD_KMS_KEY_IDprodAWS KMS key — when set, data keys wrap via KMS instead of the env key
KEYCLOAK_ISSUERagent flowOIDC issuer for end-user tokens (any OIDC IdP works)
KEYWARD_DEV_IDPdemo=1 enables the built-in demo IdP + native accounts (signup/login/2FA)
KEYWARD_HUMAN_ISSUER / _JWKS_URIprod authexternal human IdP (Clerk/WorkOS/Keycloak) for the admin surface
KEYWARD_ADMIN_TOKENdev onlyshared admin token — honored only when no human IdP is configured
KEYWARD_AUDIT_RETENTION_DAYSoptionalboot-time audit prune
KEYWARD_SIEM_WEBHOOK_URL / _TOKEN / _STDOUToptionalreal-time audit streaming sinks
KEYWARD_SCIM_TOKEN / _ORGoptionalenables SCIM 2.0 provisioning
KEYWARD_APPROVAL_TTLoptionalseconds an approval stays consumable (default 3600)
PORTplatformdefaults to 8787

Dashboard (Vercel)

Deploy apps/dashboard as the project root. Set CONTROL_PLANE_URL to the broker's public URL. Humans sign in with Keyward-native accounts (the session drives every console page); the shared KEYWARD_ADMIN_TOKEN is a local-dev convenience the broker ignores once a human IdP is configured.

Auth modes

Demo / trial: KEYWARD_DEV_IDP=1 makes the broker self-sufficient — it issues end-user tokens at /idp/token and verifies them in-process, and native signup/login/2FA work out of the box. Production: turn it off and point KEYCLOAK_ISSUER (agents) and KEYWARD_HUMAN_ISSUER (humans) at your real IdPs — same JWKS verification path, no code change.