feat(basevideo): shared-token auth with browser login page - #799
Open
thusser wants to merge 1 commit into
Open
Conversation
Add a token: str | None = None parameter to BaseVideo. When set, the MJPEG/raw/FITS endpoints require either Authorization: Bearer <token> or an HMAC-signed session cookie issued by a new /login page (/logout clears it); /ping stays open. Cookie is stateless (expiry + HMAC-SHA256 over the expiry, keyed by the token), constant-time compares throughout, routes gated on the token. web_handler translates a 401 into a 303 to /login so browsers land on the form; stream handlers check auth before prepare() and raw_handler before activate_camera(). HttpFile gains a public headers property so consumers (pyobs-gui VideoWidget, separate PR) can read the Authorization header without reaching into _headers. Implements specs/plans/2026-08-21-basevideo-http-token-auth.md.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements
specs/plans/2026-08-21-basevideo-http-token-auth.md(server-side half).What
Adds an opt-in
token: str | None = Noneparameter toBaseVideo(pyobs/modules/camera/basevideo.py). When set, all content endpoints (/,/video.mjpg,/video.raw,/{filename}) require eitherAuthorization: Bearer <token>or a valid HMAC-signed session cookie:_check_auth(request)— same contract asHttpFileCache._check_auth: no-op without a token, otherwise401unless Bearer header or cookie verifies; constant-time compares (hmac.compare_digest) throughout."<expiry_ts>.<hex HMAC-SHA256(key=token, msg=str(expiry_ts))>", 24 h lifetime,HttpOnly,SameSite=Lax,path=/. Rotating the token invalidates all cookies at once./login(GET form + POST verify,303+ cookie on success,401after a short delay on failure) and/logout(clears cookie,303 → /login) — registered only when a token is configured.web_handlertranslates the401into303 → /loginso a browser landing on/reaches the login form; the streaming handlers check auth beforeresponse.prepare(), andraw_handlerbeforeactivate_camera()(unauthenticated requests never wake the camera)./pingstays open.HttpFilegains a public read-onlyheadersproperty (pyobs/vfs/httpfile.py) so consumers don't reach into_headers.Tests
tests/modules/camera/test_basevideo.py(unit style, no TestClient): route gating,401/303behavior per endpoint, Bearer accept/reject, login POST success/failure, cookie accept / tampered / expired / cross-token rejection, logout clearing,raw_handlernot activating the camera on bad credentials,401raised beforeStreamResponse.prepare().tests/vfs/test_httpfile.pycovers theheadersproperty.token=Nonedefault behavior unchanged (existing tests untouched).HttpFile.headers.pyobs/pyobs-gui(same feature branch name, one consumer change):VideoWidgetnow sends theAuthorizationheader on its raw-socket MJPEG GET.With
tokenset, the GUI live view breaks until the pyobs-gui half lands — merge both PRs together.Out of scope (per plan): CORS for
BaseVideoendpoints, per-user accounts/Keycloak, other unauthenticated HTTP servers, browser page features beyond the login form.