Designing a Reusable Authorization Layer

As the number of GraphQL operations grows, repeating authorization logic directly inside resolvers becomes difficult to maintain.

A reusable authorization service can centralize policies:

const authorization = {
  canReadUser(actor, target) {
    return actor.id === target.id || actor.role === "ADMIN";
  },

  canUpdateUser(actor, target) {
    return actor.id === target.id || actor.role === "ADMIN";
  },

  canDeleteUser(actor, target) {
    return actor.role === "ADMIN";
  }
};

Resolvers then become simpler:

const resolvers = {
  Mutation: {
    deleteUser: async (_, { id }, context) => {
      const target = await context.userService.findById(id);

      if (!context.authorization.canDeleteUser(context.user, target)) {
        throw new Error("Forbidden");
      }

      return context.userService.deleteUser(id);
    }
  }
};

This separation gives the application a central place to test authorization rules.

For larger organizations, authorization may become a dedicated policy engine or service. Policies can incorporate roles, resource ownership, organization membership, feature flags, geographic restrictions, subscription plans, or other business conditions.

A key principle is deny by default for sensitive operations. New fields and mutations should not accidentally become accessible simply because a developer forgot to add a permission check.

Authorization Layers
Operation-level: Can this user call the operation?
Useful for broad restrictions such as administrator-only mutations.
Resource-level: Can this user access this resource?
Checks ownership, organization membership, or resource-specific policies.
Field-level: Can this user see this field?
Useful for sensitive information such as salary or private metadata.
Key Takeaways
  • Centralized authorization policies improve consistency.
  • Authorization can operate at operation, resource, and field levels.
  • Sensitive systems should generally deny access by default.
  • Authorization rules should be tested independently from GraphQL transport.
Knowledge Check

What is a major benefit of centralizing authorization policies?