feat(caddy): Audiobookshelf outside the guard chain, so the phone app works from anywhere #133

Merged
dank merged 4 commits from feat/audiobookshelf-public-app-access into main 2026-11-03 01:56:51 -08:00
Showing only changes of commit aa57c1a894 - Show all commits
+17 -15
View File
@@ -11,15 +11,17 @@
# dist-server/server/auth/OidcAuthStrategy.js + objects/settings/ServerSettings.js) # dist-server/server/auth/OidcAuthStrategy.js + objects/settings/ServerSettings.js)
# rather than a forum, because each of these is a dead-login trap: # rather than a forum, because each of these is a dead-login trap:
# #
# * The browser callback URI <base>/auth/openid/callback for EVERY origin ABS is # * Two URIs per origin ABS is reached at — <base>/auth/openid/callback and
# reached at, plus <base>/auth/openid/mobile-redirect on ABS_BASE only. ABS SWAPS # <base>/auth/openid/mobile-redirect — for EVERY entry in BASES (the LAN address
# the app's own audiobookshelf://oauth for the mobile-redirect URL before the IdP # and the public vhost). ABS SWAPS the app's own audiobookshelf://oauth for the
# ever sees a redirect_uri, so registering the app scheme with authentik — the # mobile-redirect URL before the IdP ever sees a redirect_uri, so registering the
# obvious move — is what makes phone logins fail. The app scheme belongs in ABS's # app scheme with authentik — the obvious move — is what makes phone logins fail.
# authOpenIDMobileRedirectURIs list (its built-in default), not here. The mobile # The app scheme belongs in ABS's authOpenIDMobileRedirectURIs list (its built-in
# URI is registered on the LAN origin only because the phone is configured with # default), not here. The mobile URI exists on every origin because the app sends
# the LAN address: it is a non-browser client and cannot solve the guard # the one belonging to the door it was configured with: the vhost started serving
# challenge that sits in front of the vhost. # non-browser clients on 2026-11-03 (it left the guard chain), so a phone pointed
# at the public name sends the public mobile-redirect URI, and STRICT matching
# answers an unregistered one with "Redirect URI Error".
# * <base> CARRIES THE BASE PATH. ABS builds redirect_uri as # * <base> CARRIES THE BASE PATH. ABS builds redirect_uri as
# <origin><authOpenIDSubfolderForRedirectURLs>/auth/openid/callback, and that subfolder is # <origin><authOpenIDSubfolderForRedirectURLs>/auth/openid/callback, and that subfolder is
# the ROUTER_BASE_PATH the container is mounted at — /audiobookshelf, which is also the only # the ROUTER_BASE_PATH the container is mounted at — /audiobookshelf, which is also the only
@@ -157,12 +159,12 @@ _ns = {}
exec(_src, _ns) exec(_src, _ns)
# --- provider -------------------------------------------------------------------- # --- provider --------------------------------------------------------------------
# One browser callback per origin (LAN address and the guarded vhost), because ABS # One callback pair per origin (LAN address and the public vhost): ABS derives the
# derives redirect_uri from the request origin; the mobile URI stays on the LAN origin. # browser callback from the request origin and the mobile callback from the door the
uris = [RedirectURI(matching_mode=RedirectURIMatchingMode.STRICT, # app was configured with, so each origin needs both or that door cannot sign in.
url="%s/auth/openid/callback" % b) for b in BASES] uris = [RedirectURI(matching_mode=RedirectURIMatchingMode.STRICT, url="%s%s" % (b, p))
uris.append(RedirectURI(matching_mode=RedirectURIMatchingMode.STRICT, for b in BASES
url="%s/auth/openid/mobile-redirect" % BASE)) for p in ("/auth/openid/callback", "/auth/openid/mobile-redirect")]
authz_flow = Flow.objects.get(slug="default-provider-authorization-implicit-consent") authz_flow = Flow.objects.get(slug="default-provider-authorization-implicit-consent")
# Three things beyond the name, each one a silent dead login: the grant-type list (2026.8 # Three things beyond the name, each one a silent dead login: the grant-type list (2026.8