GraphQL is growing in popularity because it allows applications to request only the data they need using a strongly-typed, self-documenting query structure that enables an API to deliver data that can evolve over time.
Unlike traditional REST APIs, GraphQL exposes a single endpoint to query and mutate data. Upon learning this, one of the first questions that comes up for many developers is: “How do I implement authorization and authentication in GraphQL?”
Authorization and authentication in GraphQL can be perplexing if you are a developer coming from a REST API background. GraphQL is a surprisingly thin API layer. The spec is relatively short and is completely un-opinionated about how authorization and authentication are implemented, leaving the implementation details up to the developer.
Authorization patterns in GraphQL are quite different than in a REST API. GraphQL is not opinionated about how authorization is implemented. To quote directly from graphql.org, “Delegate authorization logic to the business logic layer.” It is up to the developer to handle authorization when using GraphQL.
GraphQL is also un-opinionated about how authentication is implemented. Authentication patterns in GraphQL, however, are very similar to patterns used in REST APIs: a user provides login credentials, an authentication token is generated and provided by the client in each subsequent request.
The implementation details for authorization and authentication in GraphQL can be a little tricky at first. With the help of a simple example GraphQL implementation, we can shed some light on how to approach these very important pieces of your API design.
Resolvers & Contexts
Resolvers are the building blocks of GraphQL used to connect the schema with the data. These functions define how to fetch data for a query and update data for a mutation. Since resolvers are simple functions that return data, they do not care about the structure of the underlying datastore.
Using Apollo, each resolver is a function that receives four parameters:
info. For the purposes of this post, we are interested in the
context argument. It is the key to handling authorization in our Apollo server.
context is passed to each resolver and contains data that each resolver can access. The importance of
context is that it is initialized at the request level, meaning we can use it to store metadata about the user making the request. This is our entry point for implementing authorization.
Let’s build a basic Apollo server:
typeDefs defines our schema: there are
Post objects that have a
title and an
authoId, and we have exposed one root query called
posts which will allow us to fetch a list of
The resolvers (in
resolvers.js) are responsible for what it means to “fetch a list of
posts resolver simply returns the contents of
posts.js. As mentioned before, GraphQL doesn’t care where the data comes from. That means, for the purposes of this simple example, our data can simply be an in-memory array. For example:
posts is an in-memory array of four
Post objects. As you can see from the
authorId on the post objects, we have posts from two different authors. Ideally, when a user makes a request for posts, we should only return the posts belonging to that user.
Now that we have the scaffolding for our Apollo server, let’s construct a
We are defining a
context object and storing a
user value in it. The user value we are defining here will be provided to each resolver through the
context object. Let’s not worry about authenticating the user just yet. Instead, we will assume that the
user has an
1 and that value will be stored in our
The resolver function for fetching posts is passed four arguments, including the
context object. Using
context, we are able to access the current user’s
id and only return posts that belong to that user:
This demonstrates how we can leverage the
context object to have resolver-level visibility into who is trying to access the data.
Of course, we could expand this: instead of simply passing an
id for the user, we could easily pass a more complex object containing
permissions. For example:
If we assume we have a value of
admin as a possible role, we now have the ability to let a user see a post if they own it OR they are an admin!
With an understanding of how to approach authorization in GraphQL, the next step is to figure out how we can authenticate a user so we can use a real value in the
Similar to authorization, GraphQL is not opinionated about how you go about implementing authentication. It is up to the developer to define a system for taking user authentication credentials, verifying them, and giving the user access.
There are plenty of options when it comes to implementing authorization. For this example, we will implement a simple authentication system using JSON Web Tokens (JWT). JWT is used to securely send information between two parties as a JSON object, using a digital signature to verify the information has not been changed and can be trusted.
Let’s start off by updating the resolvers and schemas from before to allow us to authenticate a user.
We have added a new Mutation called
login that will allow us to handle login credentials provided by the client. To help handle the authentication logic, we have created an
auth-service uses JWT to generate a token that contains the
roles of the authenticated user and that can be handed down to the client to stored in the
Authorization header and be used in subsequent requests. For this example, the actual authentication logic is trivial, simply checking that the email and password values are not empty. This logic can be updated to fit your authentication needs.
Next, let’s look at the updated
As we saw in the resolvers, there is a new mutation available to us:
login which will return the authenticated JWT.
The function responsible for constructing the
context object has access to the request via the
req parameter. This allows the context construction function to access the
authorization header, grab the token, handle the case when the token does not exist, and then validate the token allowing us to get the user data encoded in it. Now that we have access to an authenticated user’s data, we can use this during authorization to make sure we are only returning data the user is allowed to see.
Using the API
login method is used to dispatch a query to the Apollo API, providing the email and password from the user. The response contains a JWT token that we add to the axios client default headers for each subsequent request. When we then make a request for posts in the
posts method, the response will contain all of the posts the user is authorized to see.
Authorization and authentication are fundamentally important pieces of API design. With many developers coming from a REST API background, making the leap to GraphQL can be confusing at first. This confusion stems from the fact that implementing authorization and authentication in GraphQL is left up to the developer. Using the example code provided in this post, you can create a fully functional GraphQL server using Apollo, complete with authorization and authentication.
The complete and functional example files are available here:
Interested in more software development tips & insights? Visit the development section on our blog!
We’re hiring! Looking for software engineers, product managers, and designers to join our teams in SF, LA, NYC, CHA.
Learn more and apply at www.carbonfive.com/careers