Field-Level Authorization
GraphQL makes field-level access particularly important because clients can request arbitrary combinations of fields allowed by the schema.
Consider:
type User {
id: ID!
name: String!
email: String!
salary: Float
}
Suppose administrators can see salary, but ordinary users cannot.
A resolver can enforce the policy:
const resolvers = {
User: {
salary: (user, _, context) => {
if (context.user?.role !== "ADMIN") {
throw new Error("Forbidden");
}
return user.salary;
}
}
};
This demonstrates an important GraphQL security principle: authorization cannot be applied only to top-level operations.
If a user can access a User object through a permitted query but one field contains sensitive information, that field itself may require authorization.
However, putting large authorization blocks inside individual field resolvers can become difficult to maintain. Larger systems may use reusable policy functions, directives, middleware, schema wrappers, or dedicated authorization services.
The correct choice depends on framework capabilities and application complexity.
Because clients can select individual fields and nested relationships, sensitive-field authorization must be considered independently from top-level operation authorization.
- Sensitive GraphQL fields may require their own authorization rules.
- Top-level authorization does not automatically protect every nested field.
- Reusable authorization policies reduce duplicated resolver logic.
- Field-level security is especially important for sensitive data.
Why might a sensitive GraphQL field require its own authorization check?