Implement Authentication Middleware

Create src/middleware/socket-auth.js.

The middleware should:

  1. Read the token from the handshake authentication payload.
  2. Reject missing credentials.
  3. Verify the JWT signature.
  4. Validate important claims such as expiration and subject.
  5. Store the verified identity inside socket.data.
  6. Allow the connection to continue.

The socket.data object is useful for storing information associated with the current connection.

JWT Secret Management

JWT_SECRET must be a strong secret stored securely in environment configuration. Never expose it to the browser or commit it to source control. If your identity provider uses asymmetric signing, verify using the corresponding trusted public key instead.

src/middleware/socket-auth.js
import jwt from 'jsonwebtoken';

export function socketAuth(socket, next) {
  const token = socket.handshake.auth?.token;

  if (typeof token !== 'string' || token.length === 0) {
    return next(new Error('Authentication required'));
  }

  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET, {
      algorithms: ['HS256'],
      issuer: 'chat-api',
      audience: 'chat-client'
    });

    if (
      typeof payload !== 'object' ||
      typeof payload.sub !== 'string' ||
      payload.sub.length === 0
    ) {
      return next(new Error('Invalid user identity'));
    }

    socket.data.userId = payload.sub;
    next();
  } catch (error) {
    next(new Error('Invalid or expired authentication token'));
  }
}

Reads the token, verifies its signature and configured claims, and stores the verified subject in socket.data. The JWT issuer, audience, algorithm, and secret must match the authentication service that issued the token.

Key Takeaways
  • Authentication middleware verifies credentials before connection.

  • Use jwt.verify(), not jwt.decode(), to authenticate a token.

  • Store verified identity in socket.data.

  • Validate issuer, audience, algorithm, and expiration.