Skip to content

GraphQL Subscription Context — WebSocket Authentication for Real-Time Events

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about Graphql Subscription Context. We cover key concepts, practical examples, and best practices to help you master this topic.

GraphQL subscription context handles Websocket authentication during the connection lifecycle, verifying tokens on connection and providing authenticated context to subscription resolvers.

What You'll Learn

  • WebSocket authentication for subscriptions
  • Connection lifecycle events
  • Secure token handling in real-time connections

Why It Matters

Subscriptions over WebSocket require different authentication handling than HTTP requests. Tokens must be verified during the initial connection, not per-event, for optimal performance.

Code Examples

// Apollo Server WebSocket authentication
const { WebSocketServer } = require('ws');
const { useServer } = require('graphql-ws/lib/use/ws');

const wsServer = new WebSocketServer({
  server: httpServer,
  path: '/graphql',
});

useServer({
  schema,
  context: async (ctx, msg, args) => {
    // Extract token from connection_init payload
    const token = ctx.connectionParams?.authorization?.replace('Bearer ', '');

    let user = null;
    if (token) {
      try {
        user = await verifyToken(token);
      } catch (e) {
        // Token invalid - connection may still proceed for public subscriptions
      }
    }

    return { user, db, loaders: createLoaders() };
  },
  onConnect: (ctx) => {
    // Connection lifecycle: validate on connect
    console.log('WebSocket connected');
  },
  onDisconnect: (ctx) => {
    // Cleanup when client disconnects
    console.log('WebSocket disconnected');
  }
}, wsServer);
// Subscription resolvers with auth
const resolvers = {
  Subscription: {
    privateEvents: {
      subscribe: (parent, args, context) => {
        if (!context.user) {
          throw new Error('Authentication required');
        }
        return pubsub.asyncIterator(`PRIVATE_${context.user.id}`);
      }
    },
    publicEvents: {
      subscribe: (parent, args, context) => {
        // Public events available to all
        return pubsub.asyncIterator('PUBLIC_EVENTS');
      }
    }
  }
};
# Client connection with auth token
# Connection init payload
{
  "type": "connection_init",
  "payload": {
    "authorization": "Bearer eyJhbGci..."
  }
}

# GraphQL over WebSocket subscription
wscat -c wss://api.example.com/graphql \
  -H "Sec-WebSocket-Protocol: graphql-ws"
# Send connection init with token
// Client-side WebSocket auth
import { createClient } from 'graphql-ws';

const client = createClient({
  url: 'wss://api.example.com/graphql',
  connectionParams: async () => {
    const token = await getAuthToken();
    return {
      authorization: `Bearer ${token}`
    };
  }
});

Common Mistakes

1. Per-Message Authentication

Verify token once on connection, not on every event. Per-message auth adds latency.

2. Storing Tokens in the Connection URL

Tokens in URLs are logged by proxies. Use connectionParams for secure token passing.

3. Not Handling Token Expiration

Implement reconnection logic when tokens expire during long-lived connections.

4. Allowing Unauthenticated Access to Private Subscriptions

Check authentication in subscription resolvers, not just on connect.

5. Not Cleaning Up on Disconnect

Release resources and unsubscribe from event channels when clients disconnect.

Practice Questions

  1. How do you pass auth tokens during WebSocket connection?
  2. When should you verify the auth token for subscriptions?
  3. How do you handle authentication in subscription resolvers?
  4. What happens when a token expires during an active subscription?
  5. How do you clean up resources on disconnect?

Answers:

  1. Via the connectionParams in the connection_init message.
  2. During the initial WebSocket connection, not per-event.
  3. Check context.user in the subscribe resolver.
  4. Implement client-side reconnection with a new token.
  5. Listen to the onDisconnect event and release subscription resources.

Challenge: Build a subscription system with WebSocket authentication that: verifies tokens on connect, handles token refresh, supports public and private subscriptions, and cleans up on disconnect.

FAQ

Can I use cookies for WebSocket authentication?

It depends on the client. Browsers can send cookies during WebSocket handshake, but it is less reliable than tokens.

How do I handle multiple authentication methods?

Check different sources (token, cookie, API key) in the context function and set user appropriately.

What is the difference between onConnect and context?

onConnect runs before context and can reject connections. Context is created per-connection and passed to resolvers.

How do I revoke a subscription when a user logs out?

Track active subscriptions per user and close them server-side when the user logs out from another device.

Can I use JWT with subscription auth?

Yes. JWT is the most common authentication method for WebSocket connections.

Mini Project

Build a real-time chat application with authenticated WebSocket subscriptions. Implement token-based auth on connect, private channel subscriptions, user presence tracking, and automatic reconnection on token refresh.

What's Next

Learn about DataLoader caching for optimizing nested queries, then explore DataLoader batching for database efficiency.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro