Skip to content

Authorization in GraphQL — Complete Guide

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about Authorization in GraphQL. We cover key concepts, practical examples, and best practices to help you master this topic.

Authorization determines what authenticated users can do. In GraphQL, authorization applies at the field, type, and operation levels. Implement authorization through middleware, resolver guards, or schema directives based on your granularity needs.

What You'll Learn

  • Role-based access control (RBAC) patterns
  • Field-level authorization
  • Authorization directives
  • Scope and permission checking
  • Data-level access rules (ownership)

Why It Matters

Authorization protects sensitive data and prevents unauthorized actions. Field-level authorization in GraphQL lets you expose the same schema to different user roles with different visible data.

Real-World Use

GitHub's GraphQL API checks Repository permissions on every query. A user can only see repository issues if they have read access. Shopify checks store ownership and app scope permissions.

flowchart TD
    Request[Request + User Context] --> AuthCheck[Authorization Check]
    AuthCheck --> RoleCheck{Role Check}
    RoleCheck -->|Admin| FullAccess[Full Access]
    RoleCheck -->|User| UserAccess[Field & Data Rules]
    RoleCheck -->|Guest| PublicAccess[Public Fields Only]
    UserAccess --> DataCheck{Ownership Check}
    DataCheck -->|Own| Full
    DataCheck -->|Other| Limited[Limited Fields]

Teacher Mindset

Authorization should be layered. Check operation-level permissions (can mutate?), field-level permissions (can see email?), and data-level permissions (owns this record?). Use directives for declarative authorization.

Code Examples

# Example 1: Authorization directive pattern
directive @auth(requires: Role!) on OBJECT | FIELD_DEFINITION

enum Role {
  ADMIN
  EDITOR
  VIEWER
}

type User {
  id: ID!
  name: String!
  email: String! @auth(requires: ADMIN)
  role: Role!
}

type Query {
  users: [User!]! @auth(requires: ADMIN)
  me: User!
}
// Example 2: Field-level authorization in resolver
const resolvers = {
  User: {
    email: (parent, args, context) => {
      if (context.user.role !== 'ADMIN' && context.user.id !== parent.id) {
        return null;
      }
      return parent.email;
    }
  }
};
// Example 3: Data ownership check
const resolvers = {
  Mutation: {
    deleteBook: async (_, { id }, { user }) => {
      const book = await db.books.findById(id);
      if (!book) throw new Error('Not found');
      if (book.authorId !== user.id && user.role !== 'ADMIN') {
        throw new Error('Forbidden');
      }
      await db.books.delete(id);
      return true;
    }
  }
};

Common Mistakes

  • Implementing authorization only at the operation level and ignoring field access
  • Forgetting to check data ownership for mutations on owned resources
  • Hardcoding role checks instead of using configurable permission arrays
  • Not handling authorization errors with clear, distinct error codes
  • Mixing authentication and authorization logic in the same function

Practice

  1. Create an RBAC system with ADMIN, EDITOR, and VIEWER roles.
  2. Implement field-level authorization that hides user emails from non-admins.
  3. Add ownership checks to a deleteBook mutation.
  4. Create an authorization directive for schema-level protection.
  5. Challenge: Implement scope-based permissions where each role has a configurable set of allowed operations.

FAQ

What is the difference between authentication and authorization?

Authentication verifies who the user is (identity). Authorization determines what they can do (permissions).

Should I use directives or resolver guards for authorization?

Directives are declarative and schema-level. Resolver guards give more control. Use directives for simple role checks and resolver logic for complex rules.

How do I handle authorization errors?

Return a FORBIDDEN error code or throw an AuthorizationError. Use formatError to ensure consistent error formatting.

Can authorization be context-dependent?

Yes. Data-level authorization depends on the relationship between the user and the requested resource, like document ownership.

How do I test authorization rules?

Write integration tests with different user roles and verify that unauthorized fields return null or errors while authorized fields return data.

Mini Project

Add a complete authorization system to your library API. Create roles (ADMIN, EDITOR, VIEWER). Restrict book creation to EDITOR and ADMIN. Hide book revenue data from VIEWER. Allow authors to edit only their own books.

What's Next

Next, you will learn about DataLoader for solving the N+1 Problem in GraphQL resolvers.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro