v0.339.0 rejects cross-origin WebSocket connections
Strawberry now checks the Origin header of WebSocket handshakes and refuses
connections from browser pages on other origins with an HTTP 403 response.
Previously any website could open a WebSocket to your GraphQL endpoint, and the
browser would send your userβs cookies with it. Applications that authenticate
WebSockets from cookies could therefore have operations run as their users by
another website (cross-site WebSocket hijacking).
Same-origin pages and clients that donβt send an Origin header, such as mobile
apps, server-side clients and tests, are not affected.
Who needs to change something
If your frontend is served from a different origin than your GraphQL endpoint,
for example https://app.example.com talking to https://api.example.com , or a
development server on http://localhost:5173 talking to
http://localhost:8000 , its WebSocket connections are now refused. This
includes development servers that proxy WebSockets to Strawberry while rewriting
the Host header, such as Viteβs server.proxy with changeOrigin: true .
Strawberry logs a warning on the strawberry.ws logger naming the rejected
origin.
List the origins that should be able to connect in allowed_origins :
from strawberry.fastapi import GraphQLRouter
graphql_app = GraphQLRouter( schema, allowed_origins=["https://app.example.com", "http://localhost:5173"],) The option is available on every integration that supports WebSockets: ASGI,
FastAPI, AIOHTTP, Quart, Litestar (make_graphql_controller ) and Channels
(GraphQLWSConsumer ). For rules a list canβt express, override
is_websocket_origin_allowed . See
Restricting WebSocket origins
for details.
To restore the previous behaviour, pass allowed_origins=["*"] . Only do this if
your WebSocket endpoint doesnβt rely on cookies or other credentials that
browsers send automatically.
Custom integrations
Views built directly on AsyncBaseHTTPView must implement two new methods:
get_websocket_headers , which returns the handshake headers, and
reject_websocket , which refuses the handshake without accepting the
connection. Views that donβt support WebSockets can raise NotImplementedError
from both.