The upgrade handshake and JWT on upgrade
A websocket starts life as a normal HTTP GET with an Upgrade header. The server checks the request, decides whether to allow it, and either responds with 101 Switching Protocols or rejects it. Once the upgrade completes, the connection leaves HTTP behind and becomes a persistent full-duplex channel.
The websocket handshake
HTTP request, HTTP response, then the connection flips to websocket.
Browsers cannot send custom headers on a websocket connection, so the Authorization: Bearer header you use for REST does not work here. The common pattern is to pass the JWT in the query string: ws://localhost:3000?token=eyJ.... The server verifies it during the upgrade and rejects the connection if the token is missing or invalid. That way, no unauthenticated socket ever reaches your code.
import { WebSocketServer } from 'ws';
import jwt from 'jsonwebtoken';
import { Server } from 'http';
import { IncomingMessage } from 'http';
const JWT_SECRET = process.env.JWT_SECRET || 'dev';
export function attachWebSocket(httpServer: Server) {
const wss = new WebSocketServer({ noServer: true });
httpServer.on('upgrade', (req: IncomingMessage, socket, head) => {
const url = new URL(req.url || '', 'http://localhost');
const token = url.searchParams.get('token');
if (!token) {
socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n');
socket.destroy();
return;
}
try {
const payload = jwt.verify(token, JWT_SECRET) as { userId: number };
wss.handleUpgrade(req, socket, head, (ws) => {
// attach the user so handlers can see who is on the other end
(ws as any).userId = payload.userId;
wss.emit('connection', ws, req);
});
} catch {
socket.write('HTTP/1.1 403 Forbidden\r\n\r\n');
socket.destroy();
}
});
return wss;
}Verify the JWT during the upgrade. If it fails, the socket is rejected before it opens.
One detail from the code above worth keeping: noServer: true plus httpServer.on('upgrade', ...). This lets the websocket share the same port as your HTTP server. One port, one load balancer, one TLS certificate. Do not run websockets on a separate port unless you have a very specific reason.
Quiz: Quiz
Loading practiceโฆ