0
0
GraphQLquery~10 mins

GraphQL security best practices

Choose your learning style9 modes available
Introduction

GraphQL lets you ask for exactly the data you want. But without care, it can let bad users see or change data they shouldn't. Security best practices help keep your data safe.

When building a website or app that uses GraphQL to get or change data
When you want to stop people from asking too many questions at once and slowing your system
When you want to make sure only the right people can see or change certain data
When you want to protect your server from attacks that try to confuse or overload it
When you want to keep user data private and safe from hackers
Syntax
GraphQL
type Query {
  # Define what data can be read
  user(id: ID!): User
}

type Mutation {
  # Define what data can be changed
  updateUser(id: ID!, name: String): User
}

# Example of adding security checks in resolver functions
const resolvers = {
  Query: {
    user: (parent, args, context) => {
      if (!context.user) throw new Error('Not authenticated');
      // Check if user has permission
      if (!context.user.canViewUser(args.id)) throw new Error('Not authorized');
      return getUserById(args.id);
    }
  },
  Mutation: {
    updateUser: (parent, args, context) => {
      if (!context.user) throw new Error('Not authenticated');
      if (!context.user.canEditUser(args.id)) throw new Error('Not authorized');
      return updateUser(args.id, args.name);
    }
  }
};

Resolvers are where you check who is asking and what they can do.

Always check authentication (who you are) and authorization (what you can do).

Examples
This example stops anyone who is not logged in from getting user data.
GraphQL
# Example 1: Simple authentication check in resolver
const resolvers = {
  Query: {
    user: (parent, args, context) => {
      if (!context.user) throw new Error('Not authenticated');
      return getUserById(args.id);
    }
  }
};
This example only lets admins update user info.
GraphQL
# Example 2: Authorization check for editing data
const resolvers = {
  Mutation: {
    updateUser: (parent, args, context) => {
      if (!context.user) throw new Error('Not authenticated');
      if (!context.user.isAdmin) throw new Error('Not authorized');
      return updateUser(args.id, args.name);
    }
  }
};
This stops queries that are too deep, which can slow down your server.
GraphQL
# Example 3: Limiting query depth to prevent complex queries
const depthLimit = require('graphql-depth-limit');
const server = new ApolloServer({
  schema,
  validationRules: [depthLimit(5)]
});
This limits how many queries a user can make in a minute to prevent overload.
GraphQL
# Example 4: Rate limiting to stop too many requests
const rateLimit = require('graphql-rate-limit');
const server = new ApolloServer({
  schema,
  validationRules: [rateLimit({ max: 100, window: '1m' })]
});
Sample Program

This program creates a simple GraphQL server. It checks if a user is logged in before giving data. It also checks if the user is an admin before allowing updates.

GraphQL
# Sample GraphQL server with basic security checks
const { ApolloServer, gql } = require('apollo-server');

const typeDefs = gql`
  type User {
    id: ID!
    name: String
  }

  type Query {
    user(id: ID!): User
  }

  type Mutation {
    updateUser(id: ID!, name: String): User
  }
`;

const users = [
  { id: '1', name: 'Alice' },
  { id: '2', name: 'Bob' }
];

const resolvers = {
  Query: {
    user: (parent, args, context) => {
      if (!context.user) throw new Error('Not authenticated');
      const user = users.find(u => u.id === args.id);
      if (!user) throw new Error('User not found');
      return user;
    }
  },
  Mutation: {
    updateUser: (parent, args, context) => {
      if (!context.user) throw new Error('Not authenticated');
      if (!context.user.isAdmin) throw new Error('Not authorized');
      const user = users.find(u => u.id === args.id);
      if (!user) throw new Error('User not found');
      user.name = args.name;
      return user;
    }
  }
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: () => {
    // Simulate logged-in admin user
    return { user: { id: '99', isAdmin: true } };
  }
});

server.listen().then(({ url }) => {
  console.log(`Server ready at ${url}`);
});
OutputSuccess
Important Notes

Always check both authentication and authorization in your resolvers.

Use query depth limiting and rate limiting to protect your server from heavy or malicious queries.

Common mistake: trusting client input without checks can expose sensitive data.

Summary

GraphQL security means controlling who can see or change data.

Use authentication and authorization checks in your resolver functions.

Protect your server with limits on query complexity and request rates.