From 7e72126a07b162c9d978ed85e8ea8902334d24af Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 2 Nov 2026 20:29:30 -0800 Subject: [PATCH] docs(audiobookshelf): an SSO identity cannot land on an existing account authOpenIDMatchExistingBy is unset on this deployment, so ABS matches an OpenID userinfo on sub only and auto-registers everyone else. A new authentik username that equals an existing ABS username therefore dies on the unique constraint inside the callback, reported only as 'Unauthorized' - which is exactly what a future agent would hit by 'just creating a frank user' in the IdP to reach the root account. Records the two real doors (match by username, which links and keeps root, since setUserGroup refuses to downgrade a root; or a non-colliding name), and corrects the admin-membership row: akadmin is the operator's own authentik account, already granted site admin. --- serverAppConfigs-docs/Dankserver/Audiobookshelf.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/serverAppConfigs-docs/Dankserver/Audiobookshelf.md b/serverAppConfigs-docs/Dankserver/Audiobookshelf.md index bb53df6..0824b15 100644 --- a/serverAppConfigs-docs/Dankserver/Audiobookshelf.md +++ b/serverAppConfigs-docs/Dankserver/Audiobookshelf.md @@ -97,7 +97,7 @@ the local form, and the phone app offers SSO on its server-address screen. The l | Client secret | `ABS_OIDC_CLIENT_SECRET` in `~/.config/secrets/audiobookshelf` on Dankserver (mode 600; never in the repo, a URL or an argv) | | The ABS half: issuer, the four IdP URLs, claim, auto-register | `scripts/audiobookshelf-init.sh`, armed automatically when that secret exists in the credential file | | Role at first SSO sign-in | the `abs_groups` claim: `audiobookshelf_admins` → `admin`, `audiobookshelf_users` → `user`, in neither → denied (fail closed) | -| Admin group members | `akadmin` (operator stand-in) and `qa-e2e-admin` — the second is the identity the deploy gate signs in as, so the script re-adds it on every run; drop it and the gate fails, not a phone | +| Admin group members | `akadmin` (the operator's own authentik admin account — sign in as it and the claim grants site admin) and `qa-e2e-admin` (the identity the deploy gate signs in as, so the script re-adds it every run; drop it and the gate fails, not a phone) | The IdP saying yes is not the same as being allowed in: with `authOpenIDAutoRegister` on, a first sign-in creates the account, and the claim alone decides the type. A user in @@ -146,6 +146,16 @@ Both halves — authentik's provider row and ABS's settings — are asserted end provided by the access token)` — a fault that reads like an ABS bug and is an IdP row. Attach the built-in OpenID `openid`/`profile`/`email` mappings beside the claim mapping, which is what every working RP on this IdP carries (measured 2026-11-02). +- **With `authOpenIDMatchExistingBy` unset, an SSO identity never lands on an existing ABS + account, and a name collision is a hard denial.** In that mode `findUserFromOpenIdUserInfo` + matches on `sub` only, so every first sign-in auto-registers a NEW user; if the IdP username + equals an ABS username — the local root `frank` is the one here — the create hits the unique + constraint and the callback dies `Unauthorized`. So "create a `frank` user in authentik" does + not reach the root account: either set `authOpenIDMatchExistingBy` to `username` (links the + IdP account to the existing one, and `setUserGroup` refuses to downgrade a root — root plus an + `admin` claim is allowed, root plus `user` is denied) or pick a non-colliding IdP name. Read + off `server/models/User.js` and `server/auth/OidcAuthStrategy.js` in the pinned digest + (2026-11-02). - **The audio bind stays `:ro`.** ABS writes nothing that belongs beside the audio: its library, covers, progress and sidecar metadata all land in `/metadata` on the SSD. A writable bind would put stray writes on the spindle