Skip to content

WebSocket Authentication — Complete Guide to Secure Connections

DodaTech Updated 2026-06-28 4 min read

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

WebSocket authentication verifies client identity during the handshake using tokens, cookies, or custom headers before upgrading the HTTP connection to a persistent bidirectional stream.

What You'll Learn

  • Authentication strategies for WebSocket connections
  • Token-based auth during the HTTP upgrade handshake
  • Re-authentication for long-lived connections

Why It Matters

Unauthenticated WebSocket connections expose real-time data to anyone who knows the endpoint URL. Authentication ensures only authorized users establish persistent connections.

Real-World Use

Durga Antivirus Pro WebSocket threat feed requires JWT tokens in the connection URL query string. The server validates the token during the upgrade handshake and drops unauthenticated connections immediately.

flowchart LR
    C["Client"] -->|"ws://server/ws?token=JWT"| H["HTTP Upgrade"]
    H --> V["Validate Token"]
    V -->|"Valid"| U["Upgrade to WebSocket"]
    V -->|"Invalid"| D["403 Forbidden"]
    U --> M["Authenticated Messages"]
    style V fill:#dbeafe,stroke:#2563eb

Code Examples

// Server-side token validation during handshake
const WebSocket = require('ws');
const jwt = require('jsonwebtoken');

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

server.on('connection', (ws, req) => {
  // Extract token from query string
  const url = new URL(req.url, 'http://localhost');
  const token = url.searchParams.get('token');

  if (!token) {
    ws.close(4001, 'Authentication required');
    return;
  }

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    ws.userId = decoded.sub;
    ws.role = decoded.role;
    console.log(`Authenticated user: ${ws.userId}`);
  } catch (err) {
    ws.close(4001, 'Invalid token');
  }
});

// Server: On subsequent messages, user identity is available
server.on('connection', (ws) => {
  ws.on('message', (msg) => {
    console.log(`Message from user ${ws.userId}: ${msg}`);
  });
});

Expected output: Client without valid token receives close code 4001; authenticated clients pass through.

// Client connecting with auth token
const WebSocket = require('ws');

async function connectWithAuth() {
  const token = await getAuthToken(); // Get JWT from auth server

  const ws = new WebSocket(`ws://api.example.com/ws?token=${token}`);

  ws.on('open', () => {
    console.log('Authenticated WebSocket connected');
  });

  ws.on('close', (code, reason) => {
    if (code === 4001) {
      console.error('Auth failed:', reason.toString());
      // Redirect to login or refresh token
    }
  });
}

connectWithAuth();

Expected output: Client includes token in URL; connection succeeds or fails with auth error code.

# FastAPI WebSocket authentication
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends, HTTPException
from fastapi.security import HTTPBearer
import jwt

app = FastAPI()
security = HTTPBearer()

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    token = websocket.query_params.get("token")
    if not token:
        await websocket.close(code=4001)
        return

    try:
        payload = jwt.decode(token, "secret", algorithms=["HS256"])
        user_id = payload["sub"]
    except jwt.PyJWTError:
        await websocket.close(code=4001)
        return

    await websocket.accept()
    try:
        while True:
            data = await websocket.receive_text()
            await websocket.send_text(f"User {user_id}: {data}")
    except WebSocketDisconnect:
        print(f"User {user_id} disconnected")

Expected output: FastAPI WebSocket authenticates via query parameter token before accepting the connection.

Common Mistakes

1. Passing Tokens in URL Query String

Query strings are logged by proxies and servers. Use cookies or Sec-WebSocket-Protocol header for sensitive tokens.

2. No Token Expiry Checking

Long-lived WebSocket connections may outlive token validity. Re-authenticate periodically or use refresh tokens.

3. Authenticating After Upgrade

Validating auth after accepting the connection wastes resources. Validate before calling accept().

4. Sending Sensitive Data in Close Frames

Close reasons are visible to JavaScript. Send generic messages (Invalid auth) instead of details (Token expired).

5. No Per-Connection Rate Limiting

Authenticated users can still flood the server. Apply per-connection rate limiting after authentication.

Practice Questions

  1. When does WebSocket authentication typically occur?
  2. Why should token validation happen before accepting the connection?
  3. What are three ways to pass authentication tokens to a WebSocket?
  4. How do you handle token expiry during a long-lived WebSocket session?
  5. Why should you avoid sending sensitive details in close reason codes?

Answers:

  1. During the HTTP upgrade handshake, before switching to the WebSocket protocol.
  2. To avoid allocating resources for unauthenticated connections.
  3. Query string parameter, cookie, or Sec-WebSocket-Protocol header.
  4. Send a re-authentication request frame, or use short-lived tokens with refresh tokens.
  5. Close reason codes and data are visible to JavaScript; revealing details helps attackers.

Challenge: Implement WebSocket authentication for a real-time chat application. Use JWT tokens in the query string, validate before upgrade, handle token expiry with a refresh mechanism, and apply per-connection rate limiting.

FAQ

Can you use HTTP cookies for WebSocket authentication?

: Yes, cookies set by the HTTP server are sent during the WebSocket handshake.

What WebSocket close code should be used for auth failure?

: 4001 (custom) is commonly used for authentication failures.

Does WebSocket authentication work with cross-origin connections?

: Yes, but CORS does not apply to WebSocket. Validate origin headers separately.

How do you re-authenticate an established WebSocket connection?

: Send an auth frame with a new token and validate it server-side without closing the connection.

Is WebSocket authentication compatible with load balancers?

: Yes, but use sticky sessions or token-based auth to re-validate on reconnect to a different backend.

Mini Project

Build a WebSocket server with multiple authentication methods: JWT in query string, cookie-based auth, and Sec-WebSocket-Protocol header. Each method validates before upgrade, logs authentication attempts, and sends close code 4001 on failure.

What's Next

Learn about WebSocket authorization for permission-based access control, or explore WebSocket security best practices for comprehensive protection.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro