3. Authorization: Checking permissions
5m

Overview

In the previous lesson, we saw how to verify a user's id by signing them in to Airlock. But there's still more work to do!

We know that Airlock has two different types of users: guests and hosts. And each type of user is only allowed to perform certain tasks. (For example, hosts can manage location listings, but guests cannot.)

Now that we've learned how to authenticate users, the next step is authorization: checking that the logged in user is allowed to perform whatever action they're trying to do.

In this lesson, we will:

  • Learn how to use context to grant access for authorized users at the level.

🔐 Authorization

As with authentication, there are multiple ways to handle authorization. First, there's the permission levels: you could restrict access to the entire API, to individual , or to individual . Then there's the implementation: you could define custom , or even let services outside of the take care of authorization! (You can learn more about each approach in the Apollo Server authorization docs.)

For Airlock, we're using field-level authorization. That means each checks whether the logged-in user has permission to access that part of the .

Let's take a closer look at authorization in Airlock by exploring the for one particular : createListing.

Inside the createListing resolver

As mentioned before, Airlock hosts can create listings for places they want to rent out to guests. When a host wants to create a new listing, the Airlock client calls the createListing .

Only hosts can create listings, so the createListing needs to have authorization guards in place to prevent guests from performing that action.

The for createListing is in the server/resolvers.js file. Recall that a is a function with four optional parameters: parent, args, context, and info. The third parameter, context, is where we'll find the userId and userRole properties that we set in the previous lesson.

In the resolvers.js file, search for the createListing . It'll look something like this:

server/resolvers.js
createListing: async (_, { listing }, { dataSources, userId, userRole }) => {
// the user needs to be logged in to create a listing
if (!userId) throw AuthenticationError();
if (userRole === "Host") {
// hosts can create listings
} else {
// throw a ForbiddenError
}
};

First, the checks whether there's an existing userId from the context object, because a user has to be logged in to create a listing. If there isn't a logged-in user, then the throws an AuthenticationError.

Next, the checks whether the userRole is a Host before it executes the logic to create the listing. If the user is not a host, then the returns an error.

Note: AuthenticationError and ForbiddenError are errors defined in the utils/errors.js file. For more information on how to create custom errors and codes, check out the Apollo Docs on error handling.

You can use a similar structure in other to make sure that only users with a certain role can access certain or . Want some more examples? Check out the resolvers for upcomingGuestBookings or updateProfile.

Practice

To implement field-level authorization, where can we define logic to ensure that only certain users can access certain parts of the graph?

Key takeaways

  • With -level authorization, each determines whether the logged-in user has permission to access a field, , or in the schema.

Up next

In the next lesson, we'll take a step back and see how to use Apollo Studio to test out our auth setup.

Previous