GraphQL Subscription Context — WebSocket Authentication for Real-Time Events
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
- How do you pass auth tokens during WebSocket connection?
- When should you verify the auth token for subscriptions?
- How do you handle authentication in subscription resolvers?
- What happens when a token expires during an active subscription?
- How do you clean up resources on disconnect?
Answers:
- Via the connectionParams in the connection_init message.
- During the initial WebSocket connection, not per-event.
- Check context.user in the subscribe resolver.
- Implement client-side reconnection with a new token.
- 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
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