Skip to content

petrova host airlock setup

SOL LOG — petrova.host Airlock Auth Setup

Section titled “SOL LOG — petrova.host Airlock Auth Setup”

Audience: operator
Frequency: one-time per environment
RTO: ~15 minutes
Related decision: docs/decisions/2026-05-10-per-user-auth-via-airlock-handoff.md


petrova.host uses Airlock’s cross-apex JWT handoff (flow F9) for authentication. No OAuth client registration in the oauthClients table is needed. The setup has two parts: registering the apex in Airlock, and setting three Vercel env vars.


petrova.host must appear in the handoff_consumers table so Airlock will mint handoff JWTs for it.

  1. Open hatch.so1.io (or hatch.devarno.cloud) and sign in as an admin.
  2. Navigate to OrbitsHandoff Consumers.
  3. Click Add apex.
  4. Enter https://petrova.host as the apex and petrova-host console as the label.
  5. Save. The in-process cache in Airlock clears within 30 seconds (TTL = 30 000 ms).

Option B — via bootstrap script (first deploy or DB migration)

Section titled “Option B — via bootstrap script (first deploy or DB migration)”
Terminal window
# From the airlock repo root:
DATABASE_URL=<production-db-url> \
HANDOFF_ALLOWED_APEXES=https://petrova.host \
npx tsx scripts/bootstrap-handoff-consumers.ts

The script is idempotent (ON CONFLICT DO NOTHING) — safe to re-run.

Terminal window
curl -s https://airlock.devarno.cloud/api/auth/handoff?return=https://petrova.host/api/auth/callback
# Expected: 302 to Airlock sign-in (not 400 "invalid return URL")

In the Vercel project for petrova.host (Settings → Environment Variables):

VariableValueNotes
SESSION_SECRETopenssl rand -hex 32≥32 chars; never reuse across projects
AIRLOCK_URLhttps://airlock.devarno.cloudOmit to use the default
PETROVA_HOST_ORIGINhttps://petrova.hostMust match the registered apex exactly

Generate SESSION_SECRET:

Terminal window
openssl rand -hex 32

Warning: Rotating SESSION_SECRET invalidates all existing __petrova_session cookies, logging every user out immediately. Rotate only intentionally.


Add to dashboard/.env.local (not committed):

AUTH_DISABLED=true
SESSION_SECRET=dev-secret-replace-me-in-production-xxx
AIRLOCK_URL=https://airlock.devarno.cloud
PETROVA_HOST_ORIGIN=http://localhost:3000

AUTH_DISABLED=true injects a fake admin session so the auth flow is skipped entirely. The module-scope guard in middleware.ts throws a fatal error if this flag is set in production.


Preview deployments (*.vercel.app) are not registered in the Airlock apex allowlist, so the auth flow will fail for them.

Options:

  • Preferred: Set AUTH_DISABLED=true in Vercel Preview environment variables (safe because the guard allows it in non-production NODE_ENV).
  • Alternative: Register the preview apex pattern — not recommended since Vercel preview URLs change per deployment.

SymptomCauseFix
Airlock returns invalid return URL (400)https://petrova.host not in handoff_consumersComplete Part 1
Callback returns 302 loopSESSION_SECRET unset or <32 charsSet correct env var in Vercel
Console shows “SESSION_SECRET is unset” 500Env var missingSee Part 2
User sees /denied after sign-inSigned-in Airlock account has role !== "admin"Grant admin role in Hatch → Crew
__petrova_session cookie not set in prodsecure: false on HTTPSEnsure VERCEL_ENV=production is set (Vercel sets this automatically)