Socket.io Authentication and Security JWT, CORS, and Best Practices
Learn how to secure your Socket.io server JWT authentication middleware, CORS configuration, rate limiting, and security best practices.
Socket.io Authentication and Security
Securing your Socket.io server is critical. This guide covers authentication, CORS, and security best practices.
1. JWT Authentication Middleware
io.use(async (socket, next) => { try { const token = socket.handshake.auth.token; if (!token) { return next(new Error("Authentication required")); } const decoded = jwt.verify(token, process.env.JWT_SECRET); const user = await User.findById(decoded._id); if (!user) { return next(new Error("User not found")); } // Attach user to socket socket.user = user; socket.userId = user._id.toString(); next(); } catch (err) { next(new Error("Authentication failed")); } });
The client sends the token in the auth option:
const socket = io(URL, { auth: { token: getCookie("token") } }); // Handle auth errors socket.on("connect_error", (err) => { if (err.message === "Authentication failed") { // Redirect to login window.location.href = "/login"; } });
2. CORS Configuration
const io = socketio(server, { cors: { origin: process.env.CLIENT_URL, // e.g., https://app.yourdomain.com methods: ["GET", "POST"], credentials: true // Allow cookies } });
Never use origin: "*" with credentials: true this is a security risk.
3. Rate Limiting
Prevent abuse by limiting events per socket:
const rateLimit = {}; const RATE_LIMIT_WINDOW = 60000; // 1 minute const RATE_LIMIT_MAX = 100; // 100 events per minute const checkRateLimit = (socket) => { const now = Date.now(); const key = socket.userId; if (!rateLimit[key]) { rateLimit[key] = { count: 1, startTime: now }; return true; } if (now - rateLimit[key].startTime > RATE_LIMIT_WINDOW) { rateLimit[key] = { count: 1, startTime: now }; return true; } rateLimit[key].count++; return rateLimit[key].count <= RATE_LIMIT_MAX; }; io.on("connection", (socket) => { socket.use((event, next) => { if (!checkRateLimit(socket)) { return next(new Error("Rate limit exceeded")); } next(); }); });
4. Input Validation
Validate all incoming data:
socket.on("message:send", (data) => { // Validate if (!data.targetUserId || !data.text) { return socket.emit("error", { message: "Missing required fields" }); } if (data.text.length > 1000) { return socket.emit("error", { message: "Message too long" }); } if (!mongoose.Types.ObjectId.isValid(data.targetUserId)) { return socket.emit("error", { message: "Invalid user ID" }); } // Process // ... });
5. Prevent Unauthorized Access
// Verify the user is authorized to join a chat socket.on("join:chat", async ({ targetUserId }) => { // Check if users are connected const connection = await ConnectionRequest.findOne({ $or: [ { fromUserId: socket.userId, toUserId: targetUserId, status: "accepted" }, { fromUserId: targetUserId, toUserId: socket.userId, status: "accepted" } ] }); if (!connection) { return socket.emit("error", { message: "Not connected with this user" }); } const roomId = getRoomId(socket.userId, targetUserId); socket.join(roomId); });
6. Handle Disconnections
io.on("connection", (socket) => { socket.on("disconnect", (reason) => { console.log(`Disconnected: ${socket.userId}, reason: ${reason}`); onlineUsers.delete(socket.userId); io.emit("user:offline", { userId: socket.userId }); }); socket.on("error", (err) => { console.error("Socket error:", err); }); });
7. Use Socket.io Admin
Monitor connections in production:
npm install @socket.io/admin-ui
const { instrument } = require("@socket.io/admin-ui"); instrument(io, { auth: { type: "basic", username: "admin", password: process.env.ADMIN_PASSWORD }, mode: "development" // or "production" });
Security Checklist
- JWT authentication on every connection
- CORS configured with specific origin
- credentials: true for cookies
- Rate limiting on events
- Input validation on all events
- Authorization checks (can user join this room?)
- Handle disconnections and clean up
- No sensitive data in events
- HTTPS/WSS in production
- Socket.io admin for monitoring
The Takeaway
Socket.io security involves: JWT authentication middleware (verify token, attach user to socket), CORS with specific origin and credentials, rate limiting per user, input validation on all events, authorization checks (can the user join this room?), proper disconnection handling, no sensitive data in events, HTTPS/WSS in production, and monitoring with Socket.io Admin. Never use origin: "*" with credentials: true.
Use io.use() middleware: read the token from socket.handshake.auth.token, verify with jwt.verify(), find the user, and attach to socket.user. The client passes the token in the auth option: io(url, { auth: { token } }). Handle connect_error for auth failures.
Pass cors option when creating the server: socketio(server, { cors: { origin: process.env.CLIENT_URL, methods: ['GET', 'POST'], credentials: true } }). Use a specific origin (not '*'), and enable credentials for cookie-based auth. Never combine origin: '*' with credentials: true.
Use socket.use() middleware to check a rate limit map per user. Track event count and start time. If count exceeds the limit within the window, return next(new Error('Rate limit exceeded')). This prevents abuse like spamming messages.
Before allowing a user to join a chat room, check if they are connected with the target user (ConnectionRequest with status 'accepted'). If not connected, reject with an error event. This prevents users from joining chats with people they're not connected to.
A dashboard for monitoring Socket.io connections in real-time. Install @socket.io/admin/ui, instrument your io instance with basic auth. View active connections, rooms, events, and disconnect users. Useful for debugging and monitoring production.
Ready to master Node.js completely?
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.
Master Node.js
Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course.

