A namespace is a separate channel over one connection, addressed by path: io.of('/shop') and io.of('/admin') have their own handlers, middleware and rooms, so user:u7 in one is a different room from user:u7 in the other. Use namespaces for concerns with different authorization, and rooms — arbitrary labels a socket joins and leaves — for the fan-out sets inside them. Every socket also sits in a room named after its own id, which is how io.to(socketId).emit() works. Socket middleware runs once per connection, during the handshake, so since that handshake bypassed Express 24,430 , this is where you re-do authentication.
function authenticate(socket, next) {
const user = sessions[socket.handshake.auth.token]; // or handshake.headers.cookie
if (!user) return next(new Error('unauthorized')); // client sees a connect_error
socket.data.user = user;
next();
}
const shop = io.of('/shop');
shop.use(authenticate); // per namespace: io.use() only covers "/"
shop.on('connection', (socket) => {
socket.join(`user:${socket.data.user.id}`); // one room per user, all their devices
console.log('/shop join', socket.data.user.id, '| rooms',
[...socket.rooms].filter((r) => r !== socket.id));
});
const admin = io.of('/admin');
admin.use(authenticate);
admin.use((s, next) => (s.data.user.role === 'admin' ? next() : next(new Error('forbidden'))));
admin.on('connection', (socket) => {
socket.on('discount', ({ userId, percent }) => {
shop.to(`user:${userId}`).emit('discount', { percent }); // cross-namespace push
console.log('/admin sent', percent + '% to user:' + userId);
});
});Four clients: a reader and a bad token on /shop, that reader and an admin on /admin.
$ node ns-server.js $ node ns-client.js
/shop join u7 | rooms [ 'user:u7' ] bad token on /shop -> unauthorized
/admin sent 15% to user:u7 reader on /admin -> forbidden
reader got discount 15%The reader was accepted on /shop, rejected on /admin by the second middleware, and the admin's event reached the reader's room without knowing which socket or device was listening. Rejections arrive as connect_error with your message, so keep those messages vague, as in Error Middleware.