Authentication and Authorization in GraphQL (and how GraphQL-Modules can help)
After a few years of working with GraphQL, as open-source developers and as infrastructure team in large enterprises, we’ve learned some lessons about GraphQL, and how to authenticate and authorize GraphQL API.
Authentication and authorization should be simple, because for most cases, it’s just a piece of code that we wish to run before letting users access certain resources.
In this article we’ll go through all the different ways of implementing authentication and authorization, the benefits and downsides to each one, and offer a solution that we believe is the best philosophy to do so.
Authentication / Authorization?
I found good answer in StackOverflow covers the main differences between authentication and authorization:
In this article, I’ll cover the difference between authentication and authorization with GraphQL APIs, explain how to implement them with GraphQL server, and with the GraphQL-Modules framework.
We learned that a good implementation for GraphQL authentication has the following features regarding authentication:
- Your authentication implementation should eventually provide the
currentUserto the resolvers
- Your resolvers should not know about the authentication logic (separation between the business logic and the authentication logic)
- You wish to protect only parts of your GraphQL schema, and not all of it.
- You want to be able to authenticate parts of your schema, on a
And the following features regarding authorization:
- You wish to protect some fields, according to custom rules.
- You wish to run custom logics that protects parts of your GraphQL schema.
- Our custom rules should not be coupled to a specific resolver.
Where to put your authentication?
To understand why implementing authentication in GraphQL might be tricky, let’s start with the following chart:
A request comes from the network, go through a HTTP server (for example,
express) — That’s #1 in the chart.
Then it goes through GraphQL server, which builds a
, and then it runs your
resolvers — #2.
Then, you have your business logic, that you might want to separate from the resolvers, that’s #3.
Basically, you can implement GraphQL authentication on each part of this chart. But there are differences between those points that might effect the behaviour of your server, and might limit you later doing some things.
Let’s focus on the features requirements I mentioned before, and try to understand how the implementation selection might effect you.
So let’s take #1:
If you implement your authentication on #1 (between the network request and the HTTP server), you probably does it with
express middleware or something similar.
The benefit in this is the separation between authentication logic and your business logic. But, you can’t connect your data from the HTTP request to your GraphQL server, and it might be difficult later to get access to the
currentUser. It also protects the entire GraphQL endpoint, and not only parts of it.
So that’s nice, but not perfect.
Implementing authentication as part of your resolver code or business logic code isn’t a good idea. It usually means that your app code knows too much about the authentication, and it’s probably coupled to it.
It’s might to simpler to implement, but much more difficult to reuse later.
You can implement authentication between your HTTP server and your GraphQL server, by using the GraphQL
By implementing a custom
context building function, you can access the network request and build your
context object, and add
to it. Then, your
resolvers getting called by the GraphQL engine.
From our experience, we can tell that implementing authentication in this part of your GraphQL server gives you control over your authentication flow, if it’s done right.
In the next chapter we’ll dive in, and see how easy it’s to implement in with Apollo-Server.
Getting Started with Authentication
We’ll start by implementing a simple authentication flow in GraphQL server (using Apollo-Server 2.0).
I’m assuming that you already have your own favorite way to authenticate, whether it’s with headers, cookies or any other way. In the point of view of the server, we expect to get a token, and we’ll assume that it comes from the headers for the simplicity.
Let’s start by creating a simple Apollo-Server instance, with a very simple schema. We’ll focus on exposing the
currentUser as a query field.
Now, let’s implement
context , and see if we can get a valid user out of the values we get there.
Our goal in this part is only to validate the token, and try to trade it for a user.
If the token or the user are not valid — we don’t want to throw an exception here, because that way, our server will not support public queries.
So we just trying to get a user and a token, and return them to Apollo-Server, so it will use it as the
context for our resolvers. If something went wrong with the validation — we just return
null for the
Note that in a good GraphQL server implementation, the
contextis built once per request, and shouldn’t change over time. So they only way to modify it is using the
contextfunction that builds it before the resolver getting called.
Now, we can finally implement the
resolvers for the server:
This is a naive implementation, that assumes that the token is valid, because otherwise the
context.currentUser will be
That leads us to the next steps: implementing guards.
To add guards to your resolvers, you can use a simple Middleware approach, and wrap your resolver with a function that checks if
context.user is valid, and otherwise, throws an error.
You are getting full control over your authentication flow, because you can choose which resolvers to wrap.
So let’s implement a simple guard, and use it in our server.
I also added a public part of the schema (
Query.serverTime), that should be public, and not effected by the authentication flow. So it’s not wrapped with our guard.
Great! So now our server is authenticated and we can get the
currentUser in our resolvers.
It also protects only the part of the GraphQL schema that we wanted to protect, and the authentication flow is separated from the resolvers, so each resolver does only what it needs.
Getting Started with Authorization
Now that we understand the concept of authentication in GraphQL servers, we can also implement authorization.
Implementing Authorization is no different than implementing the
authenticated guard we did before. It’s just another guard, or resolver wrapper we can use.
type Article to the schema, and allow creating article only to users with
role set to
EDITOR . It’s that simple:
Next-Level implementation with GraphQL-Modules
If you wish to take your GraphQL server to the next level, and build a scalable, testable and readable server, I recommend to give GraphQL-Modules a try.
With GraphQL-Modules, you can separate your schema to smaller pieces, and creates modules that are in-charge of small parts of your code.
It also provides a
resolversComposition feature, that acts like a powerful middleware mechanism, that let you write your modules without knowing about the authentication flow, and just wrap your resolvers with guards in the app-level, so modules are independent and do only what they need, and the app that uses these modules decide which resolvers to authenticate.
It also super powerful, because you can implement your GraphQL-Module as standalone module, use it in multiple applications, and then apply different authentication/authorization rules in each app.
To implement the same example above with GraphQL-Modules, you can create a module called
auth and move the
context building logic to there.
Then, create another module called
common and the general parts, and
articles to manage the articles features.
This way — each module is in charge of a different feature of our app.
The Future of Authentication with GraphQL-Modules and GraphQL @directives
If you wish to get rid of the
resolversComposition wrapping, and use a more declarative way, you can use GraphQL directives to decorate your schema and put the authentication/authorization there.
To get started, add the following @directives to your
auth module’s schema:
Then, you can easily alter your
resolversComposition into a function that accepts
GraphQLSchema , and then check using your schema object, which resolves require which logic, and do a mapping:
The, you add the directives to your schema declaration:
Another thing we are working on, is having some of your repeated authentication and authorization logic installable through npm!
You can read this blog post to learn to use this library with GraphQL-Modules in a few steps;
Authentication and authorization is a fundamental part of your GraphQL server.
It should be easy and secure to implement and understand how to do that in order to help grow the GraphQL community
In this article we wanted to give you a complete overview of authentication and authorization in the GraphQL ecosystem and give you the tools and the knowledge to implement it on your GraphQL servers.
Please try all those different approaches and let us know your feedback about the best way for you and if we can improve it even further.
All posts about GraphQL Modules
- GraphQL Modules — Feature based GraphQL Modules at scale
- Why is True Modular Encapsulation So Important in Large-Scale GraphQL Projects?
- Why did we implement our own Dependency Injection library for GraphQL-Modules?
- Scoped Providers in GraphQL-Modules Dependency Injection
- Writing a GraphQL TypeScript project w/ GraphQL-Modules and GraphQL-Code-Generator
- Authentication and Authorization in GraphQL (and how GraphQL-Modules can help)
- Authentication with AccountsJS & GraphQL Modules
- Manage Circular Imports Hell with GraphQL-Modules