Rooms and Auth

Namespaces, Rooms and Authenticated Sockets

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.

Per-namespace authentication, a role check, and a per-user roomJavaScript
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.

Output of 79
$ 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.