Skip to content

5. Authentication

1. Authentication Types

1.1 Session-based Authentication with Express and Socket.IO

✅ Setup: Install dependencies

Terminal window
npm install express express-session socket.io

📄 server.js

const express = require('express');
const session = require('express-session');
const http = require('http');
const socketIO = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
// Session middleware
const sessionMiddleware = session({
secret: 'my-secret',
resave: false,
saveUninitialized: true
});
app.use(sessionMiddleware);
// Fake login route
app.get('/login', (req, res) => {
req.session.user = { id: 1, name: 'John' };
res.send('Logged in');
});
// Share session with socket.io
io.use((socket, next) => {
sessionMiddleware(socket.request, {}, next);
});
io.on('connection', (socket) => {
const session = socket.request.session;
if (session && session.user) {
console.log(`User ${session.user.name} connected`);
socket.emit('welcome', `Welcome ${session.user.name}`);
} else {
console.log('Unauthenticated connection attempt');
socket.disconnect();
}
});
server.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});

The session is shared with Socket.IO via socket.request.session.

1.2 Token-based Authentication with JWT

✅ Setup: Install dependencies

Terminal window
npm install express jsonwebtoken socket.io

📄 server.js

const express = require('express');
const jwt = require('jsonwebtoken');
const http = require('http');
const socketIO = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
const SECRET_KEY = 'your-secret-key';
// Fake login route to issue token
app.get('/login', (req, res) => {
const user = { id: 1, name: 'John' };
const token = jwt.sign(user, SECRET_KEY, { expiresIn: '1h' });
res.json({ token });
});
// Socket.IO authentication middleware
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) return next(new Error('Authentication error'));
jwt.verify(token, SECRET_KEY, (err, user) => {
if (err) return next(new Error('Authentication error'));
socket.user = user; // attach user to socket
next();
});
});
io.on('connection', (socket) => {
console.log(`User ${socket.user.name} connected`);
socket.emit('welcome', `Hello ${socket.user.name}`);
});
server.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});

🧠 Client Example for Token-based Auth:

const socket = io('http://localhost:3000', {
auth: {
token: 'your-jwt-token-here'
}
});

Summary

FeatureSession-basedToken-based (JWT)
StorageServer-side (memory/DB)Client-side (localStorage/cookie)
Use caseWeb apps with login sessionsAPIs, mobile apps, stateless auth
Socket.IO integrationsocket.request.sessionsocket.handshake.auth.token

2. Sharing Session?

2.1 🔍 Why share session with Socket.IO?

In session-based authentication, user data (e.g., login status) is stored server-side, usually via a session middleware like express-session. When using Socket.IO, it does not automatically share sessions with Express. So if a user logs in via Express, Socket.IO won’t know who they are unless you explicitly share the session with it.

  • Express sets the user session during login (req.session.user = ...).
  • Socket.IO runs in a separate context and doesn’t have access to that session by default.
  • You need the session in socket.request.session to verify if the user is logged in when a websocket connection is made.

✅ Sharing session enables this:

io.use((socket, next) => {
// Share the session set by Express
sessionMiddleware(socket.request, {}, next);
});
io.on('connection', (socket) => {
if (socket.request.session.user) {
// Now we know which user connected
console.log(`User ${socket.request.session.user.name} connected`);
} else {
console.log('Unauthenticated user tried to connect');
socket.disconnect();
}
});

2.2 When not to share session?

You may not want to share sessions with Socket.IO if you’re building a system that:

  • Doesn’t use server-side sessions at all (e.g., uses stateless auth like JWT)
  • Prefers horizontal scalability without shared session storage (sessions add complexity in scaling)
  • Is an API-first or microservices app where each service independently validates users
  • Wants to avoid memory leaks or excess memory usage from express-session’s in-memory store

✅ Example: Using JWT instead of sessions

Let’s look at an example where you purposely do NOT share the Express session with Socket.IO, and instead use JWT authentication (stateless and scalable):

server.js
const express = require('express');
const jwt = require('jsonwebtoken');
const http = require('http');
const socketIO = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
const SECRET = 'supersecret';
// Login endpoint issues token
app.get('/login', (req, res) => {
const user = { id: 1, name: 'Alice' };
const token = jwt.sign(user, SECRET, { expiresIn: '1h' });
res.json({ token });
});
// NO session middleware used here
// Auth via JWT on websocket handshake
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) return next(new Error('No token provided'));
try {
const user = jwt.verify(token, SECRET);
socket.user = user;
next();
} catch (err) {
return next(new Error('Invalid token'));
}
});
io.on('connection', (socket) => {
console.log(`User ${socket.user.name} connected`);
socket.emit('message', `Hello ${socket.user.name}`);
});
server.listen(3000, () => {
console.log('JWT-based server running on http://localhost:3000');
});
client.js example
const socket = io('http://localhost:3000', {
auth: {
token: 'your-jwt-token-here'
}
});

🔍 Summary: Why skip session sharing?

Use JWT InsteadDon’t Share Sessions
Stateless and scalableNo express-session
Easier to work across servicesNo server memory used
Better for APIs and mobile appsNo session syncing needed

So, you don’t share session when you want stateless, scalable, modern authentication.