4. Session Handling
1. What is socket.handshake in Socket.IO?
-
It’s an object containing info about the initial HTTP/WebSocket connection request.
-
Represents the handshake phase where the client and server upgrade from HTTP to WebSocket.
-
Includes details like:
headers— HTTP headers sent by the clientquery— URL query parameters from client connection URLauth— authentication data sent during connection (like tokens)time— timestamp of the handshakeaddress— client’s IP address
A WebSocket connection starts with an HTTP GET request like this:
GET /ws HTTP/1.1Host: example.comUpgrade: websocketConnection: UpgradeSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==Sec-WebSocket-Version: 13Authorization: Bearer <token> <-- custom header (optional)Cookie: sessionId=abc123 <-- or cookie (optional)The server can inspect headers and either accept or reject the connection.
1.1 Why is it called “handshake”?
Socket.IO uses a HTTP polling handshake first, then upgrades to WebSocket (or directly WebSocket if possible).
This is a higher-level handshake on top of the underlying TCP connection, which establishes the WebSocket session and exchanges metadata before real-time communication starts.
TCP handshake vs Socket.IO handshake:
| Aspect | TCP Handshake | socket.handshake in Socket.IO |
|---|---|---|
| Level | Transport Layer (TCP protocol) | Application Layer (Socket.IO/WebSocket) |
| What it does | Establishes a TCP connection (SYN, SYN-ACK, ACK) | Contains info about the HTTP/WebSocket upgrade request |
| When it happens | Before any data transfer | During the initial Socket.IO connection setup |
| Purpose | Low-level connection establishment | Exchanging metadata & authenticating clients |
1.2 Summary
socket.handshakeis metadata about the client’s connection request.- It’s not the TCP handshake, but a logical handshake at the Socket.IO layer.
- Useful for extracting headers, auth info, cookies, etc., at the time the socket connects.
2. Session Handling
2.1 Session handling in WebSockets is tricky
- Express sessions rely on HTTP cookies.
- WebSocket connections start with an HTTP handshake, then upgrade.
- After upgrade, no HTTP headers are sent, so no new cookies.
- You must extract the session cookie during the handshake and load the session manually.
2.2 Share Express sessions with Socket.IO
To share Express sessions with WebSockets:
- Set up
express-session. - Use the same session middleware with
Socket.IO’s handshake. - Access session data on socket connections.
1. Setup Express and express-session
const express = require('express');const session = require('express-session');
const app = express();
const sessionMiddleware = session({ secret: 'your-secret-key', resave: false, saveUninitialized: true, cookie: { secure: false } // set true if using HTTPS});
app.use(sessionMiddleware);2. Setup Socket.IO and share session middleware
const http = require('http');const { Server } = require('socket.io');
const server = http.createServer(app);const io = new Server(server);
// Share session middleware with Socket.IOio.use((socket, next) => { sessionMiddleware(socket.request, {}, next); // Here you are attaching the session to the socket.request during the WebSocket handshake. // This makes the session data available at socket.request.session. // Sessions are only available through socket.request.session once — during the initial connection (WebSocket handshake). // // After the handshake, regular WebSocket messages (e.g., socket.on(...)) don’t go through middleware again, // but socket.request.session still holds the session data, including any mutations you make to it. // // This means: // You can read and modify the session during the connection lifecycle. // But session persistence (e.g. saving updated values) needs a manual call to session.save().});3. Access session data inside socket connection
io.on('connection', (socket) => { const session = socket.request.session; console.log('Session ID:', session.id);
// You can read/write session properties here if (!session.views) { session.views = 0; } session.views++; session.save(); // Refer to the notes below
socket.emit('sessionData', { views: session.views });});Why in non-websockets context, session.save() is not required?
In non-WebSocket (i.e. normal HTTP) contexts, like handling a request in Express:
app.get('/some-route', (req, res) => { req.session.counter = (req.session.counter || 0) + 1; res.send(`Counter: ${req.session.counter}`);});You usually don’t need to call req.session.save() manually, because:
✅ Why session.save() is not needed in HTTP
- Automatic save at the end of the request
express-sessionautomatically detects if the session was modified, and saves it before the response ends.- It hooks into
res.end()orres.send()internally.
- Middleware lifecycle handles persistence
- When the HTTP request completes, Express finalizes the response, and
express-sessionsaves the session data to the store (memory, Redis, etc.). - This happens behind the scenes — no manual save needed.
❌ Why this doesn’t work in WebSockets:
- WebSocket events (like
socket.on('event', ...)) are not part of the Express request-response lifecycle. - There’s no
res.end()for WebSocket events — soexpress-sessionhas no signal to save the session automatically. - Therefore, you must call
socket.request.session.save()manually if you modify the session inside a WebSocket event.
🧠 Summary
| Context | session.save() needed? | Why? |
|---|---|---|
| HTTP | ❌ Not needed | Auto-saved at end of request |
| WebSocket | ✅ Required (if modified) | No auto-save trigger — must call manually |
4. Example route that initializes session data
app.get('/', (req, res) => { if (!req.session.username) { req.session.username = 'Nadith'; } res.sendFile(__dirname + '/index.html');});5. [OPTIONAL] Express + Socket.IO with Redis session store
const RedisStore = require('connect-redis')(session);const redisClient = require('redis').createClient();
const sessionMiddleware = session({ store: new RedisStore({ client: redisClient }), secret: 'your-secret-key', resave: false, saveUninitialized: false});Summary
| Step | Description |
|---|---|
Use express-session | Setup session middleware in Express |
| Share session with Socket.IO | Use io.use() to run session middleware on socket requests |
| Access session data | Read/write via socket.request.session |
| Save changes | Call session.save() if you modify session |
3. Cookies and Web Sockets
WebSocket-based connections, the HTTP cookies (including connect.sid) are only sent during the initial handshake, not after.
So how does the server identify the session in subsequent WebSocket messages?
✅ How It Works in Practice (Socket.IO + Express Sessions)
🔁 1. During Handshake:
-
The browser sends cookies:
connect.sid=abc123 -
Socket.IO middleware runs:
sessionMiddleware(socket.request, {}, next); -
This sets
socket.request.sessionwith the session data -
You can now check
socket.request.session.userIdor anything you stored
💾 2. Persist User Info in Socket
Once authenticated, store relevant session data on the socket:
io.on('connection', (socket) => { const session = socket.request.session; socket.userId = session.userId;
socket.on('message', (msg) => { console.log(`[${socket.userId}] sent: ${msg}`); });});Now you don’t need to read cookies anymore — you’re using socket.userId.
3. 🔄 What About Reconnects?
When the client disconnects and reconnects:
- A new handshake is made
- Cookies are sent again
- The session middleware runs again
session.userIdis re-attached
So the session still works seamlessly.
4. 🛡️ Summary
| Step | Mechanism |
|---|---|
| Initial handshake | Cookies are sent (e.g. connect.sid) |
| Session loaded | Via express-session middleware |
| User info stored | Attached to socket object |
| Persistent state | Session lives in memory for connection |
| Reconnects | Cookies sent again — session restored |
4. Socket.IO Middleware
Socket.IO has its own middleware system**, separate from Express.
4.1 🔧 WebSocket (Socket.IO) Middleware
Socket.IO supports connection-level middleware:
io.use((socket, next) => { // This runs during the handshake (one time per connection) const token = socket.handshake.auth.token; if (!token) return next(new Error('Unauthorized')); // Attach user info, etc. next();});And you can do application logic in event handlers like:
io.on('connection', (socket) => { socket.on('chat', (msg) => { // Handle real-time message });});4.2 🔁 Express Lifecycle vs. Socket.IO Lifecycle
| Feature | HTTP (Express) | WebSocket (Socket.IO) |
|---|---|---|
| Session auto-save | ✅ Yes | ❌ No (session.save() required) |
Uses req, res, next() | ✅ Yes | ❌ Only during handshake via socket.request |
| Middleware runs per request | ✅ Yes | ❌ Runs only once per connection |
| Custom event-based logic | ❌ Not native | ✅ Yes (socket.on(...)) |
✅ Conclusion
-
WebSocket events are not in the Express lifecycle, but Socket.IO provides its own middleware, specifically for:
- Authentication (during connection)
- Custom logic (inside
socket.on())
If you need per-event middleware, you’d have to write your own wrappers or handlers — Socket.IO doesn’t have built-in per-event middleware like Express has per-route.