docs(dev): pin AUTH_URL to the tenant subdomain
ci / e2e (pull_request) Has been skipped
ci / image (pull_request) Has been skipped
ci / shared (pull_request) Successful in 6s
ci / test (pull_request) Successful in 28s

Live-stack debugging caught this: Auth.js v5 builds the OAuth
redirect_uri from AUTH_URL, NOT from the request Host header, even
with AUTH_TRUST_HOST=true. If you visit http://acme.localhost:3000
with AUTH_URL=http://localhost:3000, Keycloak rejects the token
exchange because the PKCE cookie was set on acme.localhost but the
callback URL Auth.js sent was localhost.

Fix in dev: pin AUTH_URL to the subdomain you're testing on. In prod,
orca-proxy passes the right host via X-Forwarded-Host and AUTH_URL
is set to the apex.

Updates .env.example with a long-form note + sets AUTH_URL to the
acme tenant so a copy/paste-and-go workflow Just Works. Adds a
'AUTH_URL gotcha' callout to the local-dev section in README.

Refs: M5.1
This commit is contained in:
2026-05-19 18:04:27 +02:00
parent 3310a942f2
commit f98d20ef0d
2 changed files with 18 additions and 3 deletions
+16 -3
View File
@@ -12,8 +12,21 @@ KEYCLOAK_CLIENT_ID=dev-portal
KEYCLOAK_CLIENT_SECRET=unused-public-client
# Auth.js v5 — required for JWT signing.
# Generate with: openssl rand -base64 32
# Generate with: openssl rand -base64 32 (keep stable across restarts or
# every dev login invalidates the existing session).
AUTH_SECRET=dev-secret-change-me-do-not-ship-replace-with-32-byte-random
AUTH_URL=http://localhost:3000
# In prod we'd set AUTH_TRUST_HOST=true behind orca-proxy; dev is loopback so leave unset.
# IMPORTANT: AUTH_URL must match the exact subdomain you're using in the
# browser. Auth.js v5 builds the OAuth redirect_uri from this value (NOT
# from the request Host header, even with AUTH_TRUST_HOST=true). If you
# visit http://acme.localhost:3000 but AUTH_URL is http://localhost:3000,
# the PKCE cookie set on acme.localhost won't be readable at the localhost
# callback, and Keycloak rejects the token exchange with
# 'invalid_grant: Incorrect redirect_uri'.
#
# For a single tenant dev flow, pin AUTH_URL to the subdomain you use:
AUTH_URL=http://acme.localhost:3000
# AUTH_TRUST_HOST is on so this still works behind orca-proxy in stage/prod
# (where the actual host is known via X-Forwarded-Host).
AUTH_TRUST_HOST=true
+2
View File
@@ -38,6 +38,8 @@ make dev # next dev on http://localhost:3000
Seed login (from the dev-stack realm): `test@breakpilot.dev` / `test`.
> **AUTH_URL gotcha:** Auth.js v5 builds the OAuth `redirect_uri` from `AUTH_URL` — not from the request Host header, even with `AUTH_TRUST_HOST=true`. For multi-tenant dev work, pin `AUTH_URL` to the subdomain you log in on (e.g., `http://acme.localhost:3000`); otherwise Keycloak rejects the token exchange with `invalid_grant: Incorrect redirect_uri`. In prod, orca-proxy passes the right host via `X-Forwarded-Host` and `AUTH_URL` is set to the apex (`https://breakpilot.com`).
`make test` / `make lint` / `make typecheck` / `make build` run vitest / eslint / tsc / next build respectively.
Env vars live in `.env.example`. Copy to `.env.local` for local overrides (gitignored).