DEV Community

myougaTheAxo
myougaTheAxo

Posted on

WebSocket Implementation with Claude Code: socket.io Patterns for Real-Time Apps

WebSocket connections require careful handling of authentication, reconnection, room management, and rate limiting. Claude Code can generate production-ready socket.io implementations when given the right patterns.


CLAUDE.md for WebSocket Standards

## WebSocket Rules

### Server-side
- Library: socket.io (namespaces, rooms, reconnect built-in)
- All connections require JWT auth (verify in handshake)
- Room naming: `{type}:{id}` e.g. `room:uuid`, `user:userId`
- Event names: snake_case — `message_sent`, `user_joined`

### Security
- Message size limit: 64KB (maxHttpBufferSize)
- Rate limiting: 60 messages/minute/user
- Escape all message content (XSS prevention)

### Client-side
- Reconnection: max 5 attempts, exponential backoff
- Show connection status in UI
- Always cleanup: socket.disconnect() on component unmount
Enter fullscreen mode Exit fullscreen mode

Generating the Socket.io Server

Generate a WebSocket server using socket.io.

Requirements:
- JWT authentication (verify auth token in handshake)
- Chat room functionality (join/leave/message)
- Redis for online user presence tracking
- Rate limiting (60 messages/minute/user)
- TypeScript

Generate these files:
- src/websocket/server.ts
- src/websocket/handlers/chatHandler.ts
- src/websocket/middleware/authMiddleware.ts
- src/websocket/services/presenceService.ts
Enter fullscreen mode Exit fullscreen mode

Generated Server Structure

// src/websocket/server.ts
import { Server } from 'socket.io';
import { verifyToken } from './middleware/authMiddleware';
import { registerChatHandlers } from './handlers/chatHandler';

export function initWebSocket(httpServer: HttpServer): Server {
  const io = new Server(httpServer, {
    cors: { origin: process.env.CLIENT_URL, credentials: true },
    maxHttpBufferSize: 64 * 1024, // 64KB limit
  });

  io.use(verifyToken); // JWT auth middleware

  io.on('connection', (socket) => {
    registerChatHandlers(io, socket);

    socket.on('disconnect', (reason) => {
      // cleanup presence
    });
  });

  return io;
}
Enter fullscreen mode Exit fullscreen mode
// src/websocket/handlers/chatHandler.ts
export function registerChatHandlers(io: Server, socket: Socket) {
  socket.on('join_room', async ({ roomId }) => {
    socket.join(`room:${roomId}`);
    socket.to(`room:${roomId}`).emit('user_joined', {
      userId: socket.data.userId,
      timestamp: Date.now(),
    });
  });

  socket.on('send_message', rateLimit(60, async ({ roomId, content }) => {
    const sanitized = escapeHtml(content);
    if (sanitized.length > 1000) return;

    io.to(`room:${roomId}`).emit('message_received', {
      userId: socket.data.userId,
      content: sanitized,
      timestamp: Date.now(),
    });
  }));

  socket.on('leave_room', ({ roomId }) => {
    socket.leave(`room:${roomId}`);
    socket.to(`room:${roomId}`).emit('user_left', {
      userId: socket.data.userId,
    });
  });
}
Enter fullscreen mode Exit fullscreen mode

Client-Side Reconnection Hook

Generate a socket.io client reconnection hook (React + TypeScript).

Requirements:
- Reconnect: max 5 attempts, exponential backoff (1s, 2s, 4s, 8s, 16s)
- Track connection status: connecting/connected/disconnected/failed
- Show spinner during reconnecting
- Show "Please refresh the page" after 5 failed attempts
- Cleanup: socket.disconnect() on useEffect cleanup

Save to: src/hooks/useWebSocket.ts
Enter fullscreen mode Exit fullscreen mode

Generated hook:

type ConnectionStatus = 'connecting' | 'connected' | 'disconnected' | 'failed';

export function useWebSocket(roomId: string) {
  const [status, setStatus] = useState<ConnectionStatus>('connecting');
  const socketRef = useRef<Socket | null>(null);

  useEffect(() => {
    const socket = io(process.env.REACT_APP_WS_URL!, {
      auth: { token: getAuthToken() },
      reconnectionAttempts: 5,
      reconnectionDelay: 1000,
      reconnectionDelayMax: 16000,
    });

    socket.on('connect', () => setStatus('connected'));
    socket.on('disconnect', () => setStatus('disconnected'));
    socket.on('reconnect_failed', () => setStatus('failed'));

    socketRef.current = socket;

    return () => {
      socket.disconnect();
    };
  }, [roomId]);

  return { socket: socketRef.current, status };
}
Enter fullscreen mode Exit fullscreen mode

Testing WebSocket Handlers

Generate unit tests for the socket.io server.

Test cases:
- Valid JWT connects successfully
- Invalid JWT is rejected on connection
- join_room adds socket to correct room
- send_message broadcasts to room members only
- Rate limit exceeded  message is silently ignored
- XSS content is escaped before broadcast

Tools: vitest + socket.io-client (test client)
Save to: src/websocket/__tests__/chatHandler.test.ts
Enter fullscreen mode Exit fullscreen mode

Summary

Design WebSocket implementations with Claude Code:

  1. CLAUDE.md — Define connection rules, security limits, event naming
  2. socket.io server — JWT auth, rooms, rate limiting from the prompt
  3. Client hook — Reconnection logic and status management
  4. Tests — Verify auth, room management, and edge cases

Security Pack (¥1,480) includes /security-check for WebSocket security review — authentication gaps, missing rate limits, XSS vectors.

👉 prompt-works.jp

Myouga (@myougatheaxo) — Security-focused Claude Code engineer.

Top comments (0)