0
0
GraphqlHow-ToBeginner · 3 min read

How to Protect GraphQL Mutation with Authentication

To protect a GraphQL mutation with authentication, check the user's identity in the resolver before performing any data changes. Use the context object to access authentication info and reject unauthorized requests by throwing an error.
📐

Syntax

In GraphQL, mutations are protected by adding authentication checks inside the resolver function. The context parameter usually carries user info from the request. You verify the user and then allow or deny the mutation.

  • parent: The result from the previous resolver (usually unused here).
  • args: The input arguments for the mutation.
  • context: Contains authentication data like the logged-in user.
  • info: Metadata about the execution state.
javascript
const resolvers = {
  Mutation: {
    updateProfile: (parent, args, context, info) => {
      if (!context.user) {
        throw new Error('Authentication required');
      }
      // Proceed with mutation logic
      return updateUserProfile(args.input);
    }
  }
};
💻

Example

This example shows a simple GraphQL mutation resolver that updates a user's profile only if the user is authenticated. The context.user holds the logged-in user info. If no user is found, it throws an error to block the mutation.

javascript
const { ApolloServer, gql } = require('apollo-server');

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

  input ProfileInput {
    name: String!
  }

  type Mutation {
    updateProfile(input: ProfileInput!): User
  }

  type Query {
    me: User
  }
`;

let currentUser = { id: '1', name: 'Alice' };

const resolvers = {
  Mutation: {
    updateProfile: (parent, { input }, context) => {
      if (!context.user) {
        throw new Error('Authentication required');
      }
      // Simulate updating user profile
      currentUser.name = input.name;
      return currentUser;
    }
  },
  Query: {
    me: (parent, args, context) => context.user
  }
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: () => ({ user: currentUser }) // Simulate logged-in user
});

server.listen().then(({ url }) => {
  console.log(`Server ready at ${url}`);
});
Output
Server ready at http://localhost:4000/
⚠️

Common Pitfalls

Common mistakes when protecting mutations include:

  • Not checking authentication inside the resolver, which allows unauthorized access.
  • Assuming authentication is handled elsewhere and skipping checks in mutations.
  • Not throwing errors when the user is missing, causing silent failures or unexpected behavior.
  • Exposing sensitive mutation logic without verifying user roles or permissions.

Always validate context.user and handle errors explicitly.

javascript
const resolvers = {
  Mutation: {
    // Wrong: No authentication check
    deletePost: (parent, args, context) => {
      // Deletes post without verifying user
      return deletePostById(args.id);
    },

    // Right: Check authentication
    deletePostSecure: (parent, args, context) => {
      if (!context.user) {
        throw new Error('Authentication required');
      }
      return deletePostById(args.id);
    }
  }
};
📊

Quick Reference

Tips to protect GraphQL mutations with authentication:

  • Use context to pass user info from your server middleware.
  • Always check context.user in mutation resolvers.
  • Throw errors immediately if the user is not authenticated.
  • Consider adding role or permission checks for sensitive mutations.
  • Test your API with and without authentication to verify protection.

Key Takeaways

Always check user authentication inside mutation resolvers using the context object.
Throw an error to block unauthorized mutation attempts.
Pass user info securely to context from your server's authentication middleware.
Add role or permission checks for sensitive data changes.
Test mutations both with and without authentication to ensure protection.