Skip to content

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

@i-murray

Description

@i-murray

Describe your context

dash                      4.2.0
dash-enterprise-auth      (current)
  • Backend: FastAPI (Dash(name, backend="fastapi")); the same issue exists for the Quart backend.

Describe the bug

When a callback runs over the WebSocket transport (declared with websocket=True, or via websocket_callbacks=True), the request cookies and headers are not available on dash.callback_context. They are empty.

The HTTP transport populates these correctly (via Dash._initialize_context), but the WebSocket context builder (create_ws_context in dash/backends/ws.py) never sets cookies, headers, args, path, remote, or origin.

This breaks any authentication helper that reads the request context. In our case, running our apps on Dash Enterprise, dash_enterprise_auth.get_user_data() reads the kcIdToken cookie (or the Plotly-User-Data header on older Dash Enterprise) from callback_context.cookies. Over WebSocket it receives {}.

Steps to reproduce

from dash import Dash, html, dcc, Input, Output, ctx

app = Dash(__name__, backend="fastapi")

app.layout = html.Div([
    dcc.Input(id="q", type="text"),
    html.Div(id="out"),
])

@app.callback(Output("out", "children"), Input("q", "value"), websocket=True)
def show_cookies(value):
    # Over HTTP this is populated; over WebSocket it is empty.
    return f"cookies={dict(ctx.cookies)} headers={bool(ctx.headers)}"

if __name__ == "__main__":
    app.run(debug=True)
  1. Run the app and open it in a browser (so the request carries cookies).
  2. Type into the input to trigger the websocket=True callback.
  3. Observe ctx.cookies is {} and ctx.headers is empty.
  4. Change the callback to a normal HTTP callback (remove websocket=True) and observe the cookies/headers are present.

Expected behavior

callback_context.cookies and callback_context.headers (and args, path, remote, origin) should be populated for WebSocket callbacks just as they are for HTTP callbacks, so authentication/session helpers behave consistently across transports.

Actual behavior

callback_context.cookies/headers are empty for WebSocket callbacks, causing auth helpers such as dash_enterprise_auth.get_user_data() to fail.

Root cause

create_ws_context in dash/backends/ws.py builds the callback context but omits the request metadata that Dash._initialize_context sets for the HTTP path. The WebSocket handshake request (which carries the cookies/headers) is available in the backend WebSocket handlers (_fastapi.py / _quart.py) but is never forwarded into the context.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions