Middleware and Authentication: Securing Your GraphQL API
Learn how to secure your GraphQL API by extracting headers from your server context and validating user authentication tokens within your resolvers.

Previously in this course, we explored organizing schema files to maintain a clean codebase as our API grows. In this lesson, we move from structural organization to security: we will learn how to extract authentication headers from the request and validate user identity within our GraphQL context.
Authentication at the Gateway
In a traditional REST architecture, you might use CORS configuration or dedicated middleware to handle security. In GraphQL, because we use a single endpoint, we handle authentication primarily by inspecting the incoming HTTP request before it reaches our business logic.
The goal is to pass the user's identity—usually verified via a JSON Web Token (JWT)—into the context object. This makes the user's "authenticated state" available to every resolver that needs it, without the resolvers needing to know the details of how the token was parsed.
Extracting Headers from Context
When you set up your Apollo Server, the context function receives an object containing the req (request) object. We can use this to grab the Authorization header.
Here is how you implement the extraction logic in your server setup:
JAVASCRIPTconst { ApolloServer } = require(CE9178">'apollo-server'); const server = new ApolloServer({ typeDefs, resolvers, context: ({ req }) => { // 1. Extract the Authorization header const authHeader = req.headers.authorization || CE9178">''; // 2. Simple token parsing logic const token = authHeader.replace(CE9178">'Bearer ', CE9178">''); // 3. Validate and attach user to context const user = getUserFromToken(token); return { user }; }, });
By placing this logic in the context function, every single resolver in your API now has access to context.user. If user is null or undefined, you know the request is unauthenticated.
Validating User Authentication
Once the user object is in the context, you need to enforce security inside your resolvers. A common mistake is to try and handle this globally; however, GraphQL resolvers are the best place for granular control.
Here is a concrete example of a protected resolver:
JAVASCRIPTconst resolvers = { Query: { myProfile: (parent, args, context) => { // Check if user exists in context if (!context.user) { throw new Error(CE9178">'You must be logged in to view this profile'); } return db.users.findById(context.user.id); }, }, };
This pattern ensures that while the server processes the request, it stops execution immediately if the identity verification fails, preventing unauthorized access to your data layer. This is a fundamental concept in Authentication and Authorization: Secure System Identity Patterns applied specifically to the GraphQL execution lifecycle.
Hands-on Exercise
- Update your context: Modify your server's
contextfunction to look for a header namedx-api-key. - Implement validation: If the key is missing or invalid, do not pass a
userobject to the context. - Protect a query: Write a resolver for a new query called
adminStatsthat checkscontext.userand throws a "Forbidden" error if the user is not found or not an admin.
Common Pitfalls
- Trusting the Client: Never trust the user's claims in the header without verifying the signature of the token. Always use a library like
jsonwebtokento verify that the token was actually issued by your server. - Leaking Context: Avoid putting sensitive internal objects (like raw database connection pools) into the context. Only expose what the resolvers strictly need.
- Ignoring Errors: If authentication fails, throw a standard GraphQL error so the client can handle the failure gracefully instead of receiving a generic HTTP 500 error.
FAQ
Q: Should I use middleware or context for authentication? A: Use context. Middleware is great for HTTP-level tasks, but the GraphQL context is the idiomatic way to pass dependencies and user state into your resolvers.
Q: Can I access the request object inside a mutation?
A: Yes, the request object is available via the context argument in all resolvers, including mutations.
Recap
We have successfully bridged the gap between raw HTTP headers and our GraphQL schema. By extracting tokens in the context function and validating that identity in our resolvers, we have added a critical layer of security to our API. This pattern allows us to scale our protection logic as we add more complex queries and mutations to our project.
Up next: We will look at Advanced Error Handling, where we learn how to create custom error classes to give our clients more meaningful feedback when authentication or other logic fails.
Work with me

Laravel REST API Development
Clean, secure, well-documented Laravel REST APIs — the backend engine for your app, mobile client, or SaaS. Built by an API specialist.

Headless WordPress + Next.js Frontend Development
Keep WordPress for content, get a lightning-fast Next.js frontend. The best of both worlds — familiar editing, modern speed.


