fix(caddy): tell Audiobookshelf its real scheme so the OIDC callback validates
ABS checks every OIDC callback against the origin it believes it is served from: getRequestOrigin() is x-forwarded-proto://Host (dist-server/server/utils/requestUtils.js, read in the pinned image digest 2026-11-03). The post-auth http://:8017 listener is fed over plain http, so Caddy's own X-Forwarded-Proto is http, ABS derives http://abs.franksdank.cloud, and answers its own https callback with 400 {"message":"Invalid callback URL - must be same-origin"} Measured at the app with the callback held fixed: Host abs.franksdank.cloud alone reproduces the 400 (as does every other Host, including the bare LAN IP), and adding `X-Forwarded-Proto: https` turns it into a 302 to /application/o/authorize/ carrying the registered redirect_uri. The edge for a guarded name is TLS-only, so https is the truthful value, not a spoof; the LAN door needs nothing because there browser and server already agree on http, which is why only the guarded path was broken.
This commit is contained in:
1 parent
fadbe10420
commit
5ef141eb17
2 files changed
+18
-1
No files matched your search
+10
-1
@@ -429,7 +429,16 @@ http://:8017 {
|
||||
# convenience hop, taken post-auth so nothing reaches the app
|
||||
# pre-authentication.
|
||||
redir / /audiobookshelf/ permanent
|
||||
reverse_proxy 192.168.0.235:8000
|
||||
# Audiobookshelf validates every OIDC callback against the origin it
|
||||
# believes it is served from — getRequestOrigin() is
|
||||
# x-forwarded-proto://Host — and a mismatch is a bodiless 400
|
||||
# "Invalid callback URL - must be same-origin" before the IdP is ever
|
||||
# contacted (measured 2026-11-03). This listener is fed over plain http
|
||||
# by the outpost, so Caddy's own X-Forwarded-Proto here says http; the
|
||||
# edge for this name is TLS-only, so https is the truthful value.
|
||||
reverse_proxy 192.168.0.235:8000 {
|
||||
header_up X-Forwarded-Proto https
|
||||
}
|
||||
}
|
||||
|
||||
@prowlarr host prowlarr.franksdank.cloud
|
||||
|
||||
@@ -140,6 +140,14 @@ Both halves — authentik's provider row and ABS's settings — are asserted end
|
||||
second wall appears after the fix ships (measured 2026-11-02: the browser reached authentik,
|
||||
got `code`+`state`, and ABS still bounced to `/login?error=undefined`). The script sets
|
||||
`authorization_code` + `refresh_token`; a blueprint re-import reverts the row silently.
|
||||
- **The guarded door has to tell the truth about its scheme.** ABS validates every OIDC
|
||||
`callback` against the origin it believes it is served from — `getRequestOrigin()` is
|
||||
`x-forwarded-proto://Host` (`server/utils/requestUtils.js`, read in the pinned digest
|
||||
2026-11-03) — so behind a TLS edge that reaches the container over plain http it computes
|
||||
`http://abs.franksdank.cloud` and answers its own https callback with a 400 "Invalid callback
|
||||
URL - must be same-origin" before the IdP is ever contacted. The Caddy `:8017` route pins
|
||||
`header_up X-Forwarded-Proto https` for exactly that reason ([[Caddy]] *Guard a new vhost*);
|
||||
the LAN door needs nothing, because there browser and server agree on `http`.
|
||||
- **The claim mapping is not the whole `property_mappings` list.** A provider holding only the
|
||||
custom mapping grants a token scoped shorter than the scopes ABS requests
|
||||
(`openid profile email abs_groups`): the code is issued and exchanged normally, and ABS's
|
||||
|
||||
Reference in new issue
Block a user