This chapter follows Securing GraphQL APIs.
Authentication proves who is calling. Authorization decides which fields and rows they may see. GraphQL’s flexibility means checking only at the HTTP edge is insufficient—clients choose fields in one request.
Transport and context
Common patterns:
- Bearer JWT in
Authorization(web tokens overview) - Session cookies with CSRF protection for same-site apps
- mTLS or service tokens for server-to-server subgraphs
Parse credentials once per request and attach userId, roles, and scopes to GraphQL context. NestJS:
context: ({ req }) => ({ user: req.user, // from passport/jwt middleware}),Subscriptions authenticate in connection_init payload on the WebSocket—mirror the same rules as HTTP headers.
Field-level authorization
Hide sensitive output by returning null (if nullable) or throwing FORBIDDEN extensions when policy denies access:
@ResolveField(() => String, { nullable: true })salary(@Parent() employee: Employee, @Context() ctx: GqlContext) { if (!ctx.user.canViewCompensation(employee.id)) return null; return employee.salary;}Document whether null means “hidden” vs “missing” so clients do not leak existence unintentionally.
Object-level authorization and node(id)
Global node(id: ID!) or user(id: ...) resolvers are convenient and dangerous: attackers guess IDs. Always authorize inside the resolver before returning the object—same lesson as the ownership checks in Authorization in NestJS for REST controllers.
Gateway-level @auth directives help but must be duplicated in subgraph resolvers; never trust the router alone inside your trust boundary.
NestJS guards
Use @UseGuards(JwtAuthGuard) on resolver classes or methods. Access HTTP request via GqlExecutionContext:
import { GqlExecutionContext } from "@nestjs/graphql";
const ctx = GqlExecutionContext.create(context);const req = ctx.getContext().req;Guards run before resolvers; combine with role decorators on mutations that change billing or PII.
Authorization not only at the gateway
Federation routers can enforce coarse rules, but subgraph resolvers hold data access. A compromised subgraph behind the router still exfiltrates data if resolvers skip checks.
Treat each subgraph as a public API surface.
Subscription auth
Long-lived sockets need refresh handling: revoke tokens mid-session, close connections on logout, and validate subscription fields with the same policies as queries.
Check your understanding
Question 1 of 6
0 of 6 checked