Authentication and Authorization in GraphQL with Spring Security
Fast recall
Quick revision
Core answer
Whether you know GraphQL-over-HTTP reuses Spring Security for authentication, and you can implement per-field authorization via `@PreAuthorize` on resolver methods or a central `DataFetcherExceptionResolver`.
Enforcing authorization only at the query root, then leaking data via nested fields (e.g. `user.order.customer.email`). Or forgetting WebSocket subscription auth — the HTTP filter chain doesn't run on the upgrade handshake by default.
Discuss per-field directive-based authz (`@auth(roles: [ADMIN])`), schema stitching/federation implications, subscription auth via `graphql-transport-ws` connection_init payload, and tenant isolation via `GraphQLContext`.
Interview-ready guide
Interview answer
Authentication in a GraphQL Spring Boot API is identical to REST — a JWT filter validates the bearer token before the GraphQL engine sees the request, and the result goes into the SecurityContext. Authorization is where the GraphQL-specific concerns appear.
Why URL-based auth rules don't work:
- With REST you can write path-based rules like
/admin/**requiresROLE_ADMIN, but with GraphQL every operation hits the same/graphqlendpoint — URL rules cannot distinguish a public query from an admin mutation - The solution is method-level security:
@PreAuthorizeon resolver methods — a query requiresisAuthenticated(), a delete mutation requireshasRole('ADMIN')
The silent failure — `@EnableMethodSecurity`:
- Without
@EnableMethodSecurity,@PreAuthorizeannotations are silently ignored — everything appears to work, but no role checks actually run - This passes code review because tests typically don't exercise authorization boundaries; always write a test that verifies an unauthenticated call is rejected
Error mapping:
- When
@PreAuthorizerejects a call, Spring throwsAccessDeniedException; GraphQL always returns HTTP 200, so without explicit handling this becomes a genericINTERNAL_ERRORthat clients can't distinguish from a server bug - Register a
DataFetcherExceptionResolverthat converts it into a typed FORBIDDEN error with anextensions.codefield so clients can react programmatically
Field-level authorization:
- Inject
@AuthenticationPrincipalto get theUserDetailsdirectly in resolvers — keeps the resolver testable withoutSecurityContextHolder - Field-level auth for sensitive fields like
salaryoremailbelongs in the service layer, not the resolver — it allows reuse across resolvers and prevents auth logic from being tightly coupled to the schema shape
I recommend writing authorization tests that verify specific extensions.code values on rejected operations — without them, auth failures are indistinguishable from server errors for both clients and your own monitoring.
Authentication and Authorization in GraphQL with Spring Security
Direct Answer
Use Spring Security for authentication (JWT or session-based) at the HTTP layer — GraphQL is just HTTP. Authorization can be done at the resolver level with @PreAuthorize annotations, or at the schema level using a custom instrumentation or a library like graphql-java-extended-scalars. Keep auth logic in the service layer, not in resolvers.
Common Mistakes & Pitfalls
Enforcing authorization only at the query root, then leaking data via nested fields (e.g. user.order.customer.email). Or forgetting WebSocket subscription auth — the HTTP filter chain doesn't run on the upgrade handshake by default.
Check your understanding
Answer these without looking back at the article.
- How do you pass authentication context to DataLoader batch functions?
- How would you implement field-level authorization (e.g., hide salary field from non-HR)?
- What is the difference between @Secured and @PreAuthorize in Spring Security?
Related interview prep categories
1Want a guided curriculum order?
These modules are also sequenced in our flagship backend interview track — open it when you prefer an ordered path instead of browsing by topic.