Compare commits

..
Author SHA1 Message Date
Frank 5794b07c32 docs(audiobookshelf): the wide listener default is a decision, not a defect
The SSO paragraph left "whether an access policy should be bound to the
audiobookshelf application" open, which invites the next agent to relitigate
it. Frank's answer of 2026-11-03: accepted on purpose — every signer becomes a
listener with all libraries and downloads, no access policy on the application,
narrowing done per account in Settings -> Users. What that makes load-bearing is
authentik's own signup flow, now named in the same paragraph as the thing that
must stay operator-only.
2026-11-03 03:08:36 -08:00
dank 1a47b831ee Merge pull request 'docs(audiobookshelf): /api/login is not a route — and what auto-registration grants' (#135) from docs/abs-login-path-and-listener-shape into main 2026-11-03 03:04:05 -08:00
Frank 5be66df2bb docs(audiobookshelf): /api/login is not a route
A wrong path was mistaken for a dead break-glass credential. Local login is
POST <base>/login; /api/* is behind the bearer guard, which answers a bare 401
and logs nothing, so a bad path looks exactly like a bad password. The recorded
value bcrypt-matches users.pash, so local really is the door when authentik is
down, and the rate-limit line was protecting a path that cannot carry a login.

Also records what auto-registration actually grants, measured from the state DB
because GET /api/users returns the limited shape: every SSO signer arrives with
accessAllLibraries and download already on, and carries no local password.
2026-11-03 02:28:11 -08:00
dank d3aedd1837 Merge pull request 'Every authentik account that signs in to Audiobookshelf becomes a listener' (#134) from feat/audiobookshelf-sso-default-listener into main 2026-11-03 02:19:14 -08:00
@@ -61,6 +61,9 @@ Dankserver. Change it in **Settings → Users → frank → Password**; the secr
then holds a stale value and only matters again if the `config` bind is ever
destroyed (a fresh DB makes the script create a new owner from it).
That value is the live password, not a leftover: it bcrypt-matches `users.pash` in the state
DB (2026-11-03), so `local` does open the door when authentik is down.
A full scan is slow and runs in the background; watch the `items:` total climb,
never `/healthcheck`. It also reads files that are genuinely broken and logs
`[AudioFileScanner] Invalid data found when processing input` per file — that is
@@ -90,6 +93,15 @@ inside the user object. A client that reads `response.token` gets the empty stri
`Authorization: Bearer ` with nothing after it, and every `/api/*` call then answers `401`
as though the password were wrong.
**`POST /api/login` is not a route.** Local login is `POST <base>/login`, and the `/api`
bearer guard answers anything else with a bare `401 Unauthorized` while logging **nothing** —
no `[LocalAuth]` line — so a wrong path is indistinguishable from a wrong password unless the
journal is read too. Same family as the absent `/setup` route named in
`scripts/audiobookshelf-init.sh`. To settle a suspected stale credential without signing in:
bcrypt-compare the recorded value against `users.pash` in
`/home/dank/Containers/audiobookshelf/config/absdatabase.sqlite`, opened read-only
(`file:<path>?mode=ro`).
## Listeners (accounts)
The door is public now, so the account is the only gate between a listener and the library.
@@ -103,7 +115,14 @@ Two ways in, both per listener:
listener, because the claim grants that role to every signer. To shut a listener off,
disable or delete their user in Audiobookshelf — no IdP group membership can withhold it.
Nothing rate-limits `/audiobookshelf/api/login` — this Caddy build carries no `rate_limit`
What auto-registration hands out (read off the state DB, 2026-11-03): `accessAllLibraries:
true` and `download: true` — every household signer lands on the **whole** library with
offline downloads already on. Narrow it per account in **Settings → Users → <name>**. The DB
is the census when no admin token is at hand; `GET /api/users` returns the *limited* shape
(no `active`, no `librariesAccessible`), so a missing key there is not a denial, and an
account created by SSO has `pash` NULL with its IdP link at `extraData.authOpenIDSub`.
Nothing rate-limits `POST /audiobookshelf/login` — this Caddy build carries no `rate_limit`
module and ABS 2.37.2 ships no lockout — so the form is a guessing target exactly like
`jelly.`, `plex.` and the *arr logins already are. The mitigation is credential hygiene:
long unique passwords per listener, never a reuse of the root password.
@@ -127,12 +146,15 @@ the local form, and the phone app offers SSO on its server-address screen. The l
With `authOpenIDAutoRegister` on, a first sign-in creates the account and the claim alone
decides its type — and the claim always carries `user`, so **the IdP is now the library gate**:
any authentik account that can reach this application becomes a listener. That is the intent
(the household signs in with the accounts it already has), which makes two things worth
checking when they change: whether authentik's own invitation/signup flow stays something only
Frank drives, and whether an access policy should be bound to the `audiobookshelf` application
to narrow who may even reach the login. Revoking one person is a disable/delete of their ABS
user; revoking everyone is that policy.
any authentik account that can reach this application becomes a listener. That is the
intent (the household signs in with the accounts it already has), and its breadth is
accepted on purpose: no access policy is bound to the `audiobookshelf` application, and
the wide auto-registered default (every library, downloads on) is **not a defect to fix** —
Frank's call, 2026-11-03. Narrowing stays a per-account judgement in **Settings → Users**.
The one thing still worth watching is authentik's own invitation/signup flow: it must
remain something only Frank drives, because an account created there is a listener the
moment it signs in. Revoking one person is a disable/delete of their ABS user; revoking
everyone is that signup flow.
Both halves — authentik's provider row and ABS's settings — are asserted end to end by the Playwright gate named in *Verification*. `23-` signs in as `qa-e2e-admin` and must land inside the app with site-admin rights; `24-` signs in as the standard identity, which is in no Audiobookshelf group, and must land as a listener. Together they pin the escalation and the default: a mapping that stops granting silently locks the household out, and a mapping that over-grants turns the household into site admins.