Skip to content

Fix missing request context (cookies/headers) in WebSocket callbacks#3815

Open
i-murray wants to merge 4 commits into
plotly:devfrom
i-murray:fix/websocket-callback-request-context
Open

Fix missing request context (cookies/headers) in WebSocket callbacks#3815
i-murray wants to merge 4 commits into
plotly:devfrom
i-murray:fix/websocket-callback-request-context

Conversation

@i-murray

@i-murray i-murray commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Propagate cookies, headers, args, path, remote, and origin from the WebSocket handshake onto the callback context in create_ws_context, mirroring the HTTP path. This fixes auth helpers (e.g. dash_enterprise_auth.get_user_data) failing over the WebSocket transport because callback_context.cookies/headers were empty.

Closes #3814

Contributor Checklist

  • I have run the tests locally and they passed.
  • I have added tests, or extended existing tests, to cover any new features or bugs fixed in this PR

optionals

  • I have added entry in the CHANGELOG.md

Propagate cookies, headers, args, path, remote, and origin from the WebSocket handshake onto the callback context in create_ws_context, mirroring the HTTP path. This fixes auth helpers (e.g. dash_enterprise_auth.get_user_data) failing over the WebSocket transport because callback_context.cookies/headers were empty.
@T4rk1n

T4rk1n commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

We have another PR #3819 that uses set_context_request on the fastapi part for the same effect, I think we need both solution consolidated.

@i-murray

i-murray commented Jun 18, 2026

Copy link
Copy Markdown
Contributor Author

We have another PR #3819 that uses set_context_request on the fastapi part for the same effect, I think we need both solution consolidated.

Re: #3819: It addresses a different bug. #3819 fixes when a non-Dash path falls through to the FastAPI catch-all route (fixes #3812) by wrapping the index() render in set_current_request(request). It doesn't touch WebSocket callbacks, so it doesn't populate callback_context.cookies / headers / args / path / remote / origin for them, which is the gap this PR targets. The two changes are independent, so this one is still needed.

Re: consolidating the mechanism: I've refactored so WebSocket callbacks now reuse the same request-context path as HTTP callbacks instead of building a parallel dict:

  • Extracted the metadata population into a shared populate_request_metadata(g, adapter) helper in _utils.py, used by both the HTTP path (_initialize_context) and the WebSocket path (create_ws_context).
  • For FastAPI, the WebSocket handler now activates the request via set_current_request(websocket) / reset_current_request(token) inside the worker thread, and reads metadata through FastAPIRequestAdapter, exactly like the HTTP flow. (ContextVars don't propagate into the ThreadPoolExecutor, so activation happens via an activate_request() context-manager seam passed into run_callback_in_executor, which enters it inside the worker thread.)
  • For Quart, it captures a request snapshot from the handshake and yields it through the same activate_request().
  • callback_context.cookies / headers / args / path / remote / origin now work identically in WebSocket and HTTP callbacks (so downstream helpers like dash_enterprise_auth.get_user_data work), with no duplicated population logic.

Tests: added unit coverage for the adapter/threading seam and end-to-end tests for both FastAPI and Quart asserting cookies/headers are visible inside a WebSocket callback.

Populate callback_context request metadata (cookies/headers/args/path/
remote/origin) for WebSocket callbacks the same way as HTTP callbacks,
via a shared populate_request_metadata helper and an activate_request
seam (FastAPI uses set_current_request; Quart uses a handshake snapshot).
Adds unit and end-to-end tests for FastAPI and Quart.
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] WebSocket callbacks do not expose request cookies/headers on callback_context

3 participants