0
0
GraphqlHow-ToBeginner · 4 min read

How to Protect GraphQL Queries with Authentication

To protect a query in GraphQL, add authentication logic in the resolver by checking the user's identity from the request context. Use middleware or context setup to verify tokens or sessions before allowing query execution.
📐

Syntax

In GraphQL, authentication is usually done inside the resolver functions or middleware. The resolver receives a context object that contains user information after authentication. You check this user info before returning data.

  • context.user: holds authenticated user info.
  • throw new Error(): stops query if user is not authenticated.
javascript
const resolvers = {
  Query: {
    protectedData: (parent, args, context) => {
      if (!context.user) {
        throw new Error('Not authenticated');
      }
      return 'Secret data for ' + context.user.name;
    }
  }
};
💻

Example

This example shows a simple GraphQL server using express and express-graphql. It checks a fake token in headers and sets context.user. The protectedData query returns data only if authenticated.

javascript
const express = require('express');
const { graphqlHTTP } = require('express-graphql');
const { buildSchema } = require('graphql');

// Define schema
const schema = buildSchema(`
  type Query {
    protectedData: String
  }
`);

// Root resolver
const root = {
  protectedData: (parent, args, context) => {
    if (!context.user) {
      throw new Error('Not authenticated');
    }
    return `Hello, ${context.user.name}. This is protected data.`;
  }
};

const app = express();

// Middleware to simulate authentication
app.use((req, res, next) => {
  const token = req.headers['authorization'];
  if (token === 'Bearer validtoken') {
    req.user = { name: 'Alice' };
  }
  next();
});

app.use('/graphql', graphqlHTTP(req => ({
  schema: schema,
  rootValue: root,
  context: { user: req.user },
  graphiql: true
})));

app.listen(4000, () => console.log('Server running on http://localhost:4000/graphql'));
Output
Query: { protectedData } Response if authorized: { "data": { "protectedData": "Hello, Alice. This is protected data." } } Response if unauthorized: { "errors": [{ "message": "Not authenticated" }] }
⚠️

Common Pitfalls

  • Not passing user info in context causes authentication checks to fail.
  • Throwing errors without clear messages can confuse clients.
  • Checking authentication only on the client side is insecure; always check on server.
  • Forgetting to protect all sensitive queries or mutations leaves data exposed.
javascript
/* Wrong: No context user check */
const resolversWrong = {
  Query: {
    protectedData: () => {
      return 'Secret data'; // No authentication check
    }
  }
};

/* Right: Check context.user */
const resolversRight = {
  Query: {
    protectedData: (parent, args, context) => {
      if (!context.user) {
        throw new Error('Not authenticated');
      }
      return 'Secret data for ' + context.user.name;
    }
  }
};
📊

Quick Reference

  • Use context to pass authenticated user info to resolvers.
  • Check context.user in every protected resolver.
  • Throw errors to block unauthorized access.
  • Use middleware to verify tokens before GraphQL execution.
  • Protect both queries and mutations that expose sensitive data.

Key Takeaways

Always check user authentication inside GraphQL resolvers using the context object.
Use middleware to verify tokens and set user info before query execution.
Throw errors in resolvers to prevent unauthorized data access.
Never rely on client-side checks alone for security.
Protect all sensitive queries and mutations consistently.