Summary
The Python client (python/wifi_densepose/client/) sends no Authorization header anywhere. Against a sensing server with RUVIEW_API_TOKEN set, it simply cannot connect — there is no way to supply a credential.
The TypeScript MCP client (tools/ruview-mcp/src/http.ts) has honoured RUVIEW_API_TOKEN for some time, so this is a gap between the two clients rather than a missing feature overall.
Why now
Independent of the OAuth work (ADR-271): this is broken today, for the auth mechanism that already ships.
Done looks like
SensingClient sends Authorization: Bearer <token> when a token is configured, read from RUVIEW_API_TOKEN by default and overridable in the constructor.
- Connecting to an auth-enabled server from Python works.
- A test covers the header being sent, and the version-compat concern below.
Work items
Technical detail
git grep -n "Authorization\|RUVIEW_API_TOKEN" python/ returns nothing. python/wifi_densepose/client/{ws,mqtt,ha,primitives}.py have no credential path.
The version trap this fix must not walk into
python/pyproject.toml pins websockets>=12.0, unbounded, and the header keyword argument was renamed inside that range:
websockets ≤ 13 → extra_headers=
websockets ≥ 14 → additional_headers=
client/ws.py calls websockets.connect(...) with neither today. A naive fix works on the author's machine and raises TypeError on a user's, in whichever direction they differ. Either detect the installed version and pass the right keyword, or raise the floor to >=14 — but pick deliberately.
Python is not browser-constrained
The browser UI needs a workaround for WS authentication because browsers cannot set Authorization on an upgrade request. Python has no such limitation — websockets can set the header directly. The Python client should send the bearer on the upgrade and should not be routed through any browser-oriented ticket mechanism; that would add a round-trip and a second credential path for no benefit.
The same applies to the TS MCP client, which sends the bearer on REST but should carry it onto WS upgrades too.
Relationship to ADR-271
ADR-271 adds Cognitum OAuth as an additional, opt-in credential for /api/v1/*. RUVIEW_API_TOKEN remains supported, so this fix is worth landing on its own and is a prerequisite for the Python client participating in OAuth later — the transport plumbing is the same either way.
Note
There is no Python OAuth client anywhere in the Cognitum ecosystem today (the existing implementations are Rust and TypeScript), so the eventual Python OAuth login flow will be written from scratch. That is a separate, larger piece of work; this issue is only about sending a bearer token that the user already has.
Summary
The Python client (
python/wifi_densepose/client/) sends noAuthorizationheader anywhere. Against a sensing server withRUVIEW_API_TOKENset, it simply cannot connect — there is no way to supply a credential.The TypeScript MCP client (
tools/ruview-mcp/src/http.ts) has honouredRUVIEW_API_TOKENfor some time, so this is a gap between the two clients rather than a missing feature overall.Why now
Independent of the OAuth work (ADR-271): this is broken today, for the auth mechanism that already ships.
Done looks like
SensingClientsendsAuthorization: Bearer <token>when a token is configured, read fromRUVIEW_API_TOKENby default and overridable in the constructor.Work items
SensingClient.__init__, defaulting toRUVIEW_API_TOKENwebsocketskeyword-argument compatibility problem below — deliberately, not by discoveryTechnical detail
git grep -n "Authorization\|RUVIEW_API_TOKEN" python/returns nothing.python/wifi_densepose/client/{ws,mqtt,ha,primitives}.pyhave no credential path.The version trap this fix must not walk into
python/pyproject.tomlpinswebsockets>=12.0, unbounded, and the header keyword argument was renamed inside that range:websockets≤ 13 →extra_headers=websockets≥ 14 →additional_headers=client/ws.pycallswebsockets.connect(...)with neither today. A naive fix works on the author's machine and raisesTypeErroron a user's, in whichever direction they differ. Either detect the installed version and pass the right keyword, or raise the floor to>=14— but pick deliberately.Python is not browser-constrained
The browser UI needs a workaround for WS authentication because browsers cannot set
Authorizationon an upgrade request. Python has no such limitation —websocketscan set the header directly. The Python client should send the bearer on the upgrade and should not be routed through any browser-oriented ticket mechanism; that would add a round-trip and a second credential path for no benefit.The same applies to the TS MCP client, which sends the bearer on REST but should carry it onto WS upgrades too.
Relationship to ADR-271
ADR-271 adds Cognitum OAuth as an additional, opt-in credential for
/api/v1/*.RUVIEW_API_TOKENremains supported, so this fix is worth landing on its own and is a prerequisite for the Python client participating in OAuth later — the transport plumbing is the same either way.Note
There is no Python OAuth client anywhere in the Cognitum ecosystem today (the existing implementations are Rust and TypeScript), so the eventual Python OAuth login flow will be written from scratch. That is a separate, larger piece of work; this issue is only about sending a bearer token that the user already has.