Skip to content

CORS for WebSockets — Cross-Origin WebSocket Connections and Security

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about CORS for WebSockets. We cover key concepts, practical examples, and best practices to help you master this topic.

Websocket connections have a different CORS model than HTTP: the browser sends the Origin header during the handshake, but the server must validate it since the browser does not enforce CORS on WebSocket data frames.

What You'll Learn

  • How CORS works (and differs) for WebSockets
  • Server-side origin validation for WebSocket handshakes
  • Security considerations for cross-origin WebSocket connections

Why It Matters

Real-time applications using WebSockets need cross-origin support. Unlike HTTP CORS, WebSocket CORS relies entirely on server-side validation. DodaTech's real-time threat dashboard uses WebSockets with strict origin validation.

sequenceDiagram
    Browser->>Server: HTTP Upgrade Request
    Browser->>Server: Origin: https://app.example.com
    Server-->>Browser: 101 Switching Protocols
    Note over Server: Server MUST validate Origin
    Browser->>Server: WebSocket data frames
    Note over Server: Browser does not check CORS for frames

Code Examples

// Browser WebSocket with CORS
const ws = new WebSocket('wss://realtime.example.com/events');

// The browser sends the Origin header automatically
// during the HTTP upgrade handshake

ws.onopen = () => {
  console.log('WebSocket connected');
  ws.send(JSON.stringify({type: 'subscribe', channel: 'alerts'}));
};

ws.onmessage = (event) => {
  console.log('Received:', event.data);
};
# Server-side WebSocket origin validation in Python
import asyncio
import websockets

ALLOWED_ORIGINS = [
    'https://app.example.com',
    'https://admin.example.com',
]

async def handler(websocket):
    # Validate origin during handshake
    origin = websocket.request_headers.get('Origin', '')
    if origin not in ALLOWED_ORIGINS:
        await websocket.close(
            4001, 'Origin not allowed'
        )
        return
    print(f'WebSocket connection from allowed origin: {origin}')
    async for message in websocket:
        # Process message
        pass

async def main():
    async with websockets.serve(
        handler, '0.0.0.0', 8765
    ):
        await asyncio.Future()
// Node.js WebSocket server with origin validation
const WebSocket = require('ws');

const ALLOWED_ORIGINS = [
  'https://app.example.com',
  'https://admin.example.com'
];

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', (ws, req) => {
  const origin = req.headers.origin;

  if (!origin || !ALLOWED_ORIGINS.includes(origin)) {
    console.log(`Rejected connection from origin: ${origin}`);
    ws.close(4001, 'Origin not allowed');
    return;
  }

  console.log(`Accepted connection from: ${origin}`);
  ws.on('message', (data) => {
    ws.send(`Echo: ${data}`);
  });
});
# Test WebSocket origin validation
python3 -c "
import websockets
import asyncio

async def test():
    async with websockets.connect(
        'wss://realtime.example.com/events',
        origin='https://evil.com'
    ) as ws:
        print('Connected with evil origin')
        await ws.close()

try:
    asyncio.run(test())
except Exception as e:
    print(f'Connection rejected: {e}')
"

Common Mistakes

1. Relying on Browser CORS Enforcement for WebSockets

Browsers do not enforce CORS on WebSocket message frames. Server-side validation is essential.

2. Not Validating Origin During WebSocket Handshake

Without origin validation, any website can connect to your WebSocket server.

3. Using HTTP CORS Headers for WebSockets

WebSocket CORS is handled during the handshake, not via Access-Control-* headers.

4. Allowing All Origins in Development and Forgetting to Restrict

Production WebSocket servers must have strict origin validation.

5. Not Handling the Upgrade Request Correctly

The WebSocket upgrade request requires specific handling for CORS headers.

Practice Questions

  1. Does the browser enforce CORS on WebSocket data frames?
  2. How does the server validate WebSocket origins?
  3. What header does the browser send during the WebSocket handshake?
  4. Can WebSocket CORS use Access-Control-Allow-Origin?
  5. How do you close a WebSocket connection due to invalid origin?

Answers:

  1. No. The browser only sends the Origin header. CORS enforcement is entirely server-side.
  2. By checking the Origin header in the HTTP upgrade request against a whitelist.
  3. The Origin header, same as HTTP CORS.
  4. No. WebSocket CORS uses the Origin header during the handshake, not HTTP CORS headers.
  5. Call websocket.close(4001, 'Origin not allowed').

Challenge: Build a real-time chat application with WebSockets. Implement origin validation, multiple allowed origins, and a fallback mechanism for connections without an Origin header.

FAQ

Do all browsers send the Origin header for WebSocket connections?

Modern browsers send the Origin header automatically. However, non-browser clients (mobile apps, CLI tools) may not send it. Plan for both cases.

Can I combine HTTP CORS and WebSocket CORS on the same server?

Yes. Handle HTTP CORS with Access-Control-* headers and WebSocket CORS with Origin validation during the upgrade handshake.

What status code should I use when rejecting a WebSocket origin?

Use status code 4001 (Custom) or 4002. The WebSocket spec reserves 4000-4999 for application-specific close codes.

Does WebSocket CORS affect subprotocol negotiation?

No. Subprotocol negotiation happens after the handshake. Origin validation should occur before subprotocol negotiation.

How do I handle WebSocket CORS with load balancers?

Ensure the load balancer forwards the Origin header. Some load balancers may strip or modify the Origin header, breaking validation.

Mini Project

Build a real-time event streaming service with WebSocket support for multiple frontend applications. Implement origin validation per channel (public channels allow any origin, private channels require specific origins), add connection logging, and create a WebSocket CORS testing tool.

What's Next

Complete the CORS project to apply all CORS concepts, or explore the CORS series summary for a comprehensive review.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro