Implement Private Messaging Using Socket IDs
Socket.IO automatically creates a private room for each connected socket using its socket ID.
This means you can send an event to one specific connection using:
io.to(socketId).emit('private:message', payload);
However, socket IDs are temporary connection identifiers. They can change after reconnection and should not be treated as permanent user IDs.
For a basic demonstration, we can maintain a mapping between usernames and socket IDs.
In a production application, use authenticated user IDs and support multiple active connections per user.
Do not trust a client-provided username as an authenticated identity. Use a verified user ID from server-side authentication. Also support multiple sockets per user because a user may have multiple browser tabs or devices connected.
const onlineUsers = new Map();
io.on('connection', (socket) => {
socket.on('user:register', (username) => {
if (
typeof username !== 'string' ||
username.trim().length === 0 ||
username.length > 30
) return;
const normalizedUsername = username.trim().toLowerCase();
onlineUsers.set(normalizedUsername, socket.id);
socket.data.username = normalizedUsername;
});
socket.on('private:message', (payload, acknowledge) => {
const recipient = payload?.recipient;
const message = payload?.message;
if (
typeof recipient !== 'string' ||
typeof message !== 'string' ||
message.trim().length === 0 ||
message.length > 1000
) {
acknowledge?.({ success: false, error: 'Invalid message' });
return;
}
const recipientSocketId = onlineUsers.get(recipient.toLowerCase());
if (!recipientSocketId) {
acknowledge?.({ success: false, error: 'User is offline' });
return;
}
io.to(recipientSocketId).emit('private:message', {
sender: socket.data.username,
message: message.trim(),
timestamp: new Date().toISOString()
});
acknowledge?.({ success: true });
});
socket.on('disconnect', () => {
if (socket.data.username) {
onlineUsers.delete(socket.data.username);
}
});
});This demonstration maintains a username-to-socket mapping and uses the recipient socket ID to deliver private messages. It supports only one connection per username and is not a production identity system.
Socket IDs can be used to target individual connections.
Socket IDs are not permanent user identities.
Production messaging should use authenticated user IDs.