Implementing GraphQL Authentication
1. Understanding GraphQL Auth Challenges
| Challenge | Detail |
|---|---|
| Single endpoint | Cannot do URL-based authorization |
| Query depth | Untrusted clients can craft expensive queries |
| Nested resolvers | Auth must happen at each level |
| Introspection | Schema disclosure in prod |
2. Using JWT in GraphQL
Example: Apollo Server context
const server = new ApolloServer({
schema,
context: async ({ req }) => {
const token = req.headers.authorization?.replace("Bearer ", "");
const user = token ? await verifyJwt(token) : null;
return { user };
}
});
3. Implementing Context for Identity
| Pattern | Detail |
|---|---|
| Auth in context | Resolvers read ctx.user |
| DataLoader | Batch with user-scoped cache |
| Per-request | Never share across requests |
4. Implementing Field-Level Authorization
Example: Resolver-level check
const resolvers = {
User: {
email: (parent, _, { user }) => {
if (user.id !== parent.id && !user.roles.includes("admin")) return null;
return parent.email;
}
}
};
5. Using Directive-Based Authorization
Example: @auth directive
directive @auth(requires: Role = USER) on FIELD_DEFINITION
type Query {
adminPanel: AdminPanel @auth(requires: ADMIN)
}
6. Implementing Query Complexity Analysis
| Library | Use |
|---|---|
| graphql-cost-analysis | Assign cost weights per field |
| Limit | Reject above threshold (e.g., 1000) |
| Tiered | Higher quota for paid plans |
7. Implementing Depth Limiting
Example: graphql-depth-limit
import depthLimit from "graphql-depth-limit";
new ApolloServer({ schema, validationRules: [depthLimit(7)] });
8. Using Persisted Queries
| Aspect | Detail |
|---|---|
| Mechanism | Client sends hash; server resolves to pre-registered query |
| Benefit | Prevents arbitrary queries in prod |
| Tool | Apollo APQ, Relay persisted queries |
| Disable introspection | In prod when APQ is on |
9. Handling Errors in Resolvers
| Pattern | Detail |
|---|---|
| AuthenticationError | HTTP 401-equivalent in GraphQL |
| ForbiddenError | 403-equivalent |
| Partial response | Return data + errors; client handles |
| Mask | Hide stack traces in prod |