docs(auth): document APP_URL requirement for reverse-proxied deployments (#99) #125
No reviewers
Labels
No labels
area:auth
area:ci
area:db
area:infra
area:native
area:pwa
area:service
epic
feature
foundation
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
james/carol!125
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "99-app-url-docs"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #99. Pure docs — no code change.
Why
Self-hosters hit this on first deploy. The container binds on
0.0.0.0:3000; Carol'sappOrigin()helper falls back to the request origin whenAPP_URLis unset, so every OAuth / OIDCredirect_uricomes out pointing at the bind address. The IdP either rejects the request (the registered callback URL doesn't matchhttp://0.0.0.0:3000/...) or completes consent and tries to send the browser to an unreachable URL. The escape hatch was documented in ADR-0015 §2 but didn't appear in any self-hoster-facing doc.Changes
docs/oidc-self-hoster-guide.mdAPP_URL" section before the recipes. Spells out the format (https://<host>, no trailing slash), the failure mode without it, the explicit note that GitHub OAuth has the same requirement (both flows go through the sameappOrigin()helper), and a one-line acknowledgement of why auto-derivation fromX-Forwarded-*is deliberately not implemented (open-redirect risk if the proxy doesn't strip incoming headers).docs/oidc-self-hoster-guide.mdTroubleshootinghttp://0.0.0.0:3000" → setAPP_URL. Cross-links the prerequisite section.README.mdenv tableAPP_URLdescription shifts from passive ("Set this when…") to required ("Required for any reverse-proxied deployment").README.md"Postgres + OIDC + reverse proxy" recipeAPP_URLis mandatory for any reverse-proxied deployment.Coverage check against the ticket's acceptance criteria
0.0.0.0:3000redirect symptom.CLAUDE.mdleft alone since it's a contributor doc, not a self-hoster doc).oauth/startandoauth/callback/[provider]callappOrigin(); the GitHub provider is registered inlib/auth/oauth-providers.tsand uses those same routes) and called out in both the prerequisite section and the troubleshooting entry.Out of scope
Auto-deriving the public URL from
X-Forwarded-Proto/X-Forwarded-Host. Per the original issue: it widens the trust surface (the proxy has to be configured to strip incomingX-Forwarded-*from external requests), and a misconfiguration there is an open-redirect vector. If revisited, it'd need its own ticket and an ADR-0015 amendment.Self-hosters hit this on first deploy: the container binds on 0.0.0.0:3000, Carol's appOrigin() helper reads the request's own origin when APP_URL isn't set, and every OAuth / OIDC redirect_uri comes out pointing at the bind address. The IdP either rejects the request or completes consent and sends the browser to an unreachable URL. The escape hatch is documented in ADR-0015 §2 but wasn't surfaced in any user-facing doc. Three additions: - docs/oidc-self-hoster-guide.md picks up a top-level "Prerequisite: APP_URL" section before the recipes, spelling out the format (`https://<host>`, no trailing slash), the failure mode without it, and explicitly noting that the same requirement applies to GitHub OAuth (both go through the same appOrigin() helper). - Same file's Troubleshooting list picks up an entry for "Sign-in redirects to http://0.0.0.0:3000" pointing back at the prerequisite section. - README's `APP_URL` table entry shifts from passive ("Set this when running behind a reverse proxy…") to required ("Required for any reverse-proxied deployment"), and the "Postgres + OIDC + reverse proxy" recipe gains a callout block above the podman command. Pure docs; no code change. Auto-derivation from X-Forwarded-* is called out as deliberately not implemented (would need a separate ticket + ADR amendment per the original issue's "Out of scope" note). Closes #99. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>📊 Test coverage
Patch coverage: no testable lines changed.
Overall (
app/,lib/,db/, excluding UI per ADR-0019):Soft thresholds per ADR-0019. Coverage is informational and does not block merge.