Skip to content

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

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.

Activity

  1. Huaian666 commented on Jun 12, 2026

    @Huaian666

    hit this in prod last week 😬 had to roll back. any timeline on a fix?

  2. andredfb commented on Jun 19, 2026

    @andredfb

    Would it make sense to pass the WebSocket object directly into the callback context? I was thinking specifically of accessing the websocket.session if using session middleware.

  3. BSd3v commented on Jun 26, 2026

    @BSd3v
    Contributor

    @Huaian666 and @i-murray,

    Websockets do not use cookies and headers, there is a different methodology for this. As this would just initially drift throughout the lifecycle of the websocket. You'll need to determine if you want to build your own auth method for the websocket flow to protect it, and extend it out from there.

    You can also use your own custom_data hook that can attach to the callback.

  4. i-murray commented on Jun 27, 2026

    @i-murray
    ContributorAuthor

    @BSd3v

    That's reasonable. For my use-case I've since extended dash_enterprise_auth to cover websocket callbacks to solve this via the standard "server-side session token" pattern, and no longer need the request context.

    Do you suggest I close this issue & close my PR? (#3815)

  5. AnnMarieW commented on Jul 8, 2026

    @AnnMarieW
    Collaborator

    Hi @i-murray

    Glad you found an alternate solution.

    Closing this issue since PR 3815 has been closed.

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions