4. Auth in a supergraph


To continue with our migration plan, we need to set up the to run on the original server port (port 4000). Before we jump into the code to do that, let's take a look at how we're going to ensure that both the and the monolith are set up to handle authentication and authorization correctly. In this lesson, we will:

  • Review how auth works in Airlock's monolithic architecture
  • Learn how to propagate authorization headers from the to its s

How auth works in Airlock

Airlock has two types of users: hosts and guests. Each type of user can perform different kinds of actions.

When logged in as a host, you can:

  • create listings
  • manage bookings for your listings
  • write reviews about guests

When logged in as a guest, you can:

  • book places to stay
  • write reviews about the location and the host
  • manage your space credits

Currently, guest users are not allowed to create listings, and host users are not allowed to book places to stay.

With these business rules, our Airlock API needs to control which users can see and interact with certain in the graph. This is where authentication and authorization come in.

  • Authentication is determining whether a given user is logged in, and subsequently determining which user someone is. (They are who they say they are.)
  • Authorization is determining what a given user has permission to do or see. (They're allowed to do what they're trying to do.)

Note: First time working with auth? Check out the Authentication & Authorization side quest for a closer look at how to verify user logins and permissions in a single .

In Airlock, we're using HTTP headers, specifically the Authorization header with a Bearer token to provide our user credentials. The header looks something like this:

Authorization: Bearer user-1

Once the receives the incoming client , it retrieves the token from the request header and attempts to authenticate the user using the accounts service. After a successful authentication, the accounts service returns an object with userId and userRole, which the then adds to the contextValue object that's available to every .

Airlock uses field-level authorization. That means each checks whether the logged-in user has permission to access that part of the . They do so using the userId and userRole properties from the contextValue object.

Auth in a supergraph

In the original monolithic architecture, the received authorization headers from the client, did some logic to pull out the user information needed, then passed this information to its through the contextValue object.

In the architecture, the story remains similar. The router will receive authorization headers from the client, then pass this information to its subgraphs. Each will do the same logic to pull out the user information and pass it over to their .

Note: There are other methods of implementing authentication in a , such as using authorization in the schema, using a coprocessor or using a JWT Authentication plugin. In this course, we'll be focusing on authentication in a using header propagation. You can combine the strategies to handle a number of authentication requirements and practice "defense-in-depth". For more information on these approaches, check out this Apollo technote.

How does the pass this information to its ? And what does the subgraph need to do to pass it to its ? Let's dive into these questions and answer them in the story of "Auth in a "!

Authenticating the user

The story starts in the same way our journey does: with a request from the client to the server. This particular request includes an Authorization header that contains the logged-in user credentials.

HTTP request with auth header is sent from the browser to the router

The receives this request and starts to create its , using the as a reference to determine which to query for a particular .

The router builds a query plan to resolve the request

Next, the executes the . It starts at the top, sending a request to the . Included with this request is the Authorization header that came from the client!

But how does the know it should be passing along that header? It's all in the configuration!

Sending HTTP headers to subgraphs

When we start up the , we have the option of passing in a configuration file, using the --config flag. This allows us to customize the in many ways, such as configuring CORS (which we saw in Voyage I), , and HTTP headers.

Using the config file, we'll tell the to send the Authorization header to its with every request. We'll see this configuration in action in the next lesson.

The config file provides instructions for which headers to send to the subgraphs

Over to the subgraph

When the receives the request from the , it accesses the Authorization header from the request and attempts to authenticate the user.

If the attempt is unsuccessful, the stops and sends an AuthenticationError back to the , which then sends it right back to the client.

The subgraph attempts to authenticate the user, returning an Authentication Error to the router if unsuccessful

If the authentication is successful, then the puts together an object containing user information and makes it available in its context. This user information object can be shaped in whatever way is going to be most useful to the subgraph's , and passed through the contextValue object.

The resolves the the same way as any other : they use their and to retrieve and populate the requested data. And they can use the user information in the contextValue object to check against the specific business rules that guard their and who has access to it!

The subgraph resolves the operation using its resolver functions and data sources

Back to the router

The sends back the requested data to the , and the router continues with its , eventually combining all those responses into a single JSON object.

Finally, the sends the final JSON object back to the client. And that's the end of our 's journey!

A doodle detailing the journey of authentication in a supergraph in its entirety


Which of the following options can be included as part of a router's config file?

Key takeaways

  • In Airlock, the client sends its request to the , with the addition of an HTTP header called Authorization, which contains the current user's auth token.
  • The can be customized with a configuration file, to pass along HTTP headers to its .
  • The passes the user's auth token to the , which checks whether or not the token is valid for login.
    • If the login is unsuccessful, the throws an AuthenticationError and sends it back to the .
    • If the login is successful, the adds the current user's information to its contextValue object, which is accessible by its for -level authorization.

Up next

We've learned how to handle auth in a , so let's put everything together and implement this in code!


Share your questions and comments about this lesson

Your feedback helps us improve! If you're stuck or confused, let us know and we'll help you out. All comments are public and must follow the Apollo Code of Conduct. Note that comments that have been resolved or addressed may be removed.

You'll need a GitHub account to post below. Don't have one? Post in our Odyssey forum instead.