diff --git a/CommunityDiscordMedia.md b/CommunityDiscordMedia.md index 28df741..4c61c75 100644 --- a/CommunityDiscordMedia.md +++ b/CommunityDiscordMedia.md @@ -261,6 +261,26 @@ Same pattern as Jellyfin: Authentik is the identity, Gitea trusts it. - [ ] policy on the Authentik application: who may reach Gitea at all (e.g. `admins` + a `devs` group) - [ ] test with a non-admin Discord user; confirm admin mapping via `admins` group +### Phase 11 — MediaMTX auth through Authentik (no stream keys anywhere) +Goal: nobody holds a MediaMTX password. "May publish" = Authentik identity + `streamers` group (filled by +Discord roles); the publish path must start with the user's own name. +- MediaMTX `authMethod: http`, `authHTTPAddress: http://127.0.0.1:8080/mtx-auth` (dumpd becomes the + arbiter; reads stay open to `any`, Caddy gates viewers). MediaMTX posts user/pass/token/action/path/ip. +- **Browser (Go Live, WHEP)**: Caddy forwards Authentik's `X-Authentik-Jwt` as `Authorization: Bearer` on + the `/webrtc` hop. dumpd verifies the JWT against Authentik's JWKS (`/application/o//jwks/`), + reads `preferred_username` + `groups`, allows publish iff `path` starts with `/` and user ∈ streamers. + No `/me/stream-key`, no `streamers.json`, nothing in the browser. +- **OBS**: streamer creates an **app password** in their Authentik profile and pastes it in the dock once; + dumpd validates Basic `user:app-password` against Authentik (outpost basic-auth endpoint or the API), + same path rule. Revoking the app password revokes the stream key. +- configure.py loses the streamers section (folders are created on first publish by MediaMTX anyway; + the sweep and Jellyfin cope). Dock: "paste your Authentik app password" instead of a stream password. +- [ ] dumpd `/mtx-auth` (JWT via JWKS, Basic via Authentik, path rule, 5 s cache) +- [ ] Caddy: `header_up Authorization "Bearer {http.request.header.X-Authentik-Jwt}"` on `/webrtc/*` (replaces X-Stream-Auth) +- [ ] MediaMTX `authMethod: http`; keep `any` read; drop `authInternalUsers` +- [ ] dock + README; remove streamers from configure.py; delete `streamers.json` +- [ ] test: OBS with an app password; Go Live with no key; a non-streamer gets denied + ### Option — more clip sources (Medal, Twitch/YouTube/Kick clips, Discord uploads) Today the only clip intake is a local clipper folder synced by Syncthing. Members without that diff --git a/STATUS.md b/STATUS.md index 2d9bfb6..84d5155 100644 --- a/STATUS.md +++ b/STATUS.md @@ -76,7 +76,8 @@ Source of truth: this repo, `techy/Media-Server-Setup` on the stack's own Gitea 9. **Home archive puller** on the home box. 10. **Plugin repository** served by Caddy so Jellyfin updates the plugin from its catalog. 11. **Clip submissions** (Medal/Twitch/YouTube links, Discord uploads) — belongs to the bot. -12. **SYS-3** when transcoding or sweep speed hurts: Quick Sync, flip the plugin's policy toggle off. +12. **MediaMTX auth through Authentik** (plan phase 11): no stream keys; Go Live uses the Authentik JWT, OBS uses an Authentik app password; "streamer" = group membership from a Discord role. +13. **SYS-3** when transcoding or sweep speed hurts: Quick Sync, flip the plugin's policy toggle off. ## Verified behaviours worth remembering - **Never scp generated configs** (`mediamtx.yml`, `copyparty.conf`, `Caddyfile`, `dump-users.txt`, `.env`): a template copy wiped all streamers once. They are gitignored now; `*.example.*` are reference only.