4. Session Handling
1. What is socket.handshake in Socket.IO?
Section titled “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”?
Section titled “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:
Section titled “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
Section titled “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
Section titled “2. Session Handling”2.1 Session handling in WebSockets is tricky
Section titled “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
Section titled “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
Section titled “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
Section titled “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
Section titled “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?
Section titled “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
Section titled “✅ 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:
Section titled “❌ 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
Section titled “🧠 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
Section titled “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
Section titled “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
Section titled “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
Section titled “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)
Section titled “✅ How It Works in Practice (Socket.IO + Express Sessions)”🔁 1. During Handshake:
Section titled “🔁 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
Section titled “💾 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?
Section titled “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
Section titled “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
Section titled “4. Socket.IO Middleware”Socket.IO has its own middleware system**, separate from Express.
4.1 🔧 WebSocket (Socket.IO) Middleware
Section titled “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
Section titled “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
Section titled “✅ 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.