Add Docker/systemd deployment, documentation, extauth logout URL wiring

This commit is contained in:
2026-08-22 23:44:46 -05:00
parent 40e1cfb630
commit b4b1ba8470
10 changed files with 534 additions and 1 deletions
+64
View File
@@ -0,0 +1,64 @@
# External authentication
VibeSonic supports optional Navidrome-style externalized authentication:
a trusted reverse proxy authenticates the browser user (via whatever
mechanism it likes — OIDC, SAML, HTTP Basic Auth, a VPN identity, ...)
and asserts that identity to VibeSonic via an HTTP header. **VibeSonic
never implements OIDC or talks to an identity provider itself** — the
proxy handles authentication, VibeSonic handles users and authorization.
## Configuration
| Variable | Default | Description |
|---|---|---|
| `VIBESONIC_EXTAUTH_ENABLED` | `false` | Enable external authentication |
| `VIBESONIC_EXTAUTH_TRUSTED_SOURCES` | *(none)* | Comma-separated list of IPv4/IPv6 CIDRs (or bare IPs) that are trusted to assert identity, e.g. `127.0.0.1/32,10.0.0.5/32` |
| `VIBESONIC_EXTAUTH_USER_HEADER` | `Remote-User` | Header name carrying the authenticated username |
| `VIBESONIC_EXTAUTH_LOGOUT_URL` | *(none)* | Optional URL to send users to on logout (e.g. the proxy's own logout endpoint), instead of VibeSonic's local `/login` |
| `VIBESONIC_EXTAUTH_AUTO_CREATE_USERS` | `true` | Automatically create a VibeSonic user the first time a trusted identity is seen |
## The critical security property
**The identity header is only trusted when the actual TCP connection
peer address matches a configured trusted CIDR.** This check
(`internal/auth/extauth.go`) reads `http.Request.RemoteAddr` — the real
socket peer — never a header.
Headers like `X-Forwarded-For`, `X-Real-IP`, or `Forwarded` are
**never** consulted to decide whether the peer is trusted. Those headers
are attacker-controlled: any client can set them to anything. If
VibeSonic trusted them, an arbitrary internet client could add
`X-Forwarded-For: 127.0.0.1` and a `Remote-User: admin` header to its own
direct request and be treated as an authenticated administrator.
This is why `VIBESONIC_EXTAUTH_TRUSTED_SOURCES` has **no default** — not
`0.0.0.0/0`, not `::/0`, not RFC1918 ranges. External auth trusts nothing
until you explicitly name a network (typically `127.0.0.1/32` for a
proxy on the same host, or the proxy's specific address on a Docker
bridge network).
See `internal/auth/extauth_test.go` for the regression tests covering
this, including a test that a spoofed `X-Forwarded-For`/`X-Real-IP`/
`Forwarded` header from an untrusted peer is ignored entirely.
## How it resolves to a user
A trusted identity resolves to an ordinary VibeSonic user (with
`external_auth = 1`), never a separate "external user" type. If
`VIBESONIC_EXTAUTH_AUTO_CREATE_USERS=true` and no user with that username
exists yet, one is created with no local password. If a user with that
username already exists (created locally or by a previous external
login), it's reused.
## Interaction with native auth
External auth and native session/password login coexist: the
`Authenticate` middleware tries the session cookie first, then falls back
to the trusted-proxy header. A user can still log in with a local
password on VibeSonic's own `/login` page even when external auth is
enabled, unless their account has no password hash set (auto-created
external users start this way).
In later phases, `/rest/*` (the native Subsonic API) will authenticate
exclusively via Subsonic's own token/API-key scheme and must never be
affected by external auth's browser-cookie flow.