WebSocket Authentication: Securing Real-Time Connections
Your WebSocket server accepts any connection. Anyone can subscribe to private channels. Here is how to authenticate WebSocket connections properly.
Token-Based Authentication
import { WebSocketServer } from "ws";
import jwt from "jsonwebtoken";
const wss = new WebSocketServer({ noServer: true });
server.on("upgrade", (req, socket, head) => {
// Extract token from query string or header
const url = new URL(req.url, "http://localhost");
const token = url.searchParams.get("token");
if (\!token) {
socket.write("HTTP/1.1 401 Unauthorized
");
socket.destroy();
return;
}
try {
const user = jwt.verify(token, process.env.JWT_SECRET);
wss.handleUpgrade(req, socket, head, (ws) => {
ws.user = user;
wss.emit("connection", ws, req);
});
} catch {
socket.write("HTTP/1.1 401 Unauthorized
");
socket.destroy();
}
});
Channel Authorization
wss.on("connection", (ws) => {
ws.on("message", (data) => {
const msg = JSON.parse(data.toString());
if (msg.type === "subscribe") {
if (\!canAccess(ws.user, msg.channel)) {
ws.send(JSON.stringify({ error: "Forbidden" }));
return;
}
channels.get(msg.channel)?.add(ws);
}
});
});
Security Checklist
- Authenticate on the upgrade request, not after connection
- Use short-lived tokens (avoid long-lived session cookies)
- Implement heartbeat/ping to detect stale connections
- Rate limit message frequency per client
- Validate and sanitize all incoming messages
Part of my Production Backend Patterns series. Follow for more practical backend engineering.
Top comments (0)