# GraphQL Directive Permissions — Authorization Made Easy URL: https://www.prisma.io/blog/graphql-directive-permissions-authorization-made-easy-54c076b5368e Published: 2018-03-01 Authors: Dennis Walsh Description: Learn how GraphQL directive permissions provide a declarative way to implement authorization rules and protect data in GraphQL servers. > Blog posts describe Prisma as it was on the date shown and are not kept current. Before implementing from a post, check the documentation index at https://www.prisma.io/docs/llms.txt and the changelog at https://www.prisma.io/changelog.md. > For an index of every published post, fetch https://www.prisma.io/blog/llms.txt. Directive permissions are a declarative way of implementing authorization rules in GraphQL servers. In this article, our guest author [Dennis Walsh](https://twitter.com/lawjolla) explains how to use them in order to protect your data. > If you're interested in writing an article for our blog as well, [drop us an email](mailto\:burk@prisma.io). GraphQL servers send your app into the world wearing only its birthday suit — everything is exposed. A quick introspection query reveals all possible API operations and data structures. That [could change](https://github.com/graphql/graphql-js/issues/113), but for now, all of your operations and data are laid bare. Therefore, one might anticipate authentication and authorization are GraphQL first class citizens. But, neither of them are part of the official [spec](https://spec.graphql.org/June2018/). That lack of direction created a lot of sleepless nights for my GraphQL server development, and it wasn’t until I watched [Ryan Chenkie](https://twitter.com/ryanchenkie)’s talk about *directive permissions* that I found a solution. [Watch the video on YouTube](https://www.youtube.com/watch?v=4_Bcw7BULC8) In this post, we will first talk through a naive approach to GraphQL permissions and find out about its drawbacks. Then, we’ll discover directive permissions and learn how they provide a declarative and reusable alternative. > To play around with directive permissions, check out this Launchpad [demo](https://launchpad.graphql.com/nxp1870jl7). ## Permissions in GraphQL: A Naive Approach [#permissions-in-graphql-a-naive-approach] ### A Simple Example [#a-simple-example] When naively implemented, the code for permissions in your GraphQL server quickly becomes repetitive. Let’s start by quickly reviewing how most GraphQL servers implement permissions in a naive and simple fashion. As an example project to anchor the discussion, here’s our [GraphQL schema definition](https://www.prisma.io/blog/graphql-server-basics-the-schema-ac5e2950214e). The schema defines the API for car dealer software. ```graphql type Query { vehicles(dealership: ID!): [Vehicle!]! } type Mutation { updateVehicleAskingPrice(id: ID!, askingPrice: Int!): Vehicle } type Vehicle { id: ID! year: Int! make: String! model: Int! askingPrice: Float costBasis: Float numberOfOffers: Int } type User { id: ID! name: String! role: String! } ``` Several fields should scream *“malicious user fun”.* To protect the API, let’s make up a few permissions rules for it: * `updateVehicleAskingPrice` should be restricted to *managers* * `costBasis` should be restricted to *managers* * `numberOfOffers` should be restricted to *authenticated users* ### Naively Implementing Permissions in GraphQL Resolvers Creates Duplication and Mixes Concerns [#naively-implementing-permissions-in-graphql-resolvers-creates-duplication-and-mixes-concerns] Using [Prisma](https://www.prismagraphql.com) in combination with [Prisma bindings](https://github.com/graphcool/prisma-binding) as a data access layer, here’s how the restriction for the `updateVehicleAskingPrice` mutation can be implemented: ```js const Mutation = { updateVehicleAskingPrice: async (parent, { id, askingPrice }, context, info) => { const userId = getUserId(context) const isRequestingUserManager = await context.db.exists.User({ id: userId, role: `MANAGER`, }) if (isRequestingUserManager) { return await context.db.mutation.updateVehicle({ where: { id }, data: { askingPrice }, }) } throw new Error(`Invalid permissions, you must be a manager to update vehicle year`) }, } ``` We’re using the [`exists`](https://github.com/graphcool/prisma-binding#exists) function on the `Prisma` binding instance (*line 4*) to ensure the requesting user has proper access rights for this mutation. If this is not the case, the mutation is not performed and will fail with an “Invalid permissions”-error instead. Field-level constraints get even more interesting. Here is how we can protect the `numberOfOffers` and `costBasis` fields on `Vehicle`: ```js const Query = { vehicles: async (parent, args, context, info) => { const vehicles = await context.db.query.vehicles({ where: { dealership: args.id }, }) const user = getUser(context) return vehicles.map(vehicle => ({ ...vehicle, costBasis: user && user.role.includes(`MANAGER`) ? vehicle.costBasis : null, numberOfOffers: user ? vehicle.numberOfOffers : null, })) }, } ``` With this approach, our resolvers become cluttered with redundant permission logic. As a first improvement, we can write a \*wrapping function \*that abstracts away some of the redundant authorization logic: ```js const Query = { vehicles: async (parent, args, context, info) => { const vehicles = await context.db.query.vehicles({ where: { dealership: args.id }, }) const user = getUser(context) return protectFieldsByRole( [{ field: `costBasis`, role: `MANAGER` }, { field: `numberOfOffers`, role: `MANAGER` }], vehicles, user, ) }, } ``` That looks a lot cleaner already. However, there is no straightforward way to figure out which fields are protected. This will always require digging into the resolver implementations and actually read the code. ## A Declarative Approach to GraphQL Permissions Based on GraphQL Directives [#a-declarative-approach-to-graphql-permissions-based-on-graphql-directives] ### Embedding Permission Directives in the Schema Definition [#embedding-permission-directives-in-the-schema-definition] Contrast the above schema and resolver implementation with this schema: ```graphql directive @isAuthenticated on FIELD | FIELD_DEFINITION directive @hasRole(role: String) on FIELD | FIELD_DEFINITION ... type Mutation { updateAskingPrice(id: ID!, newPrice: Float!): Vehicle! @hasRole(role: "MANAGER") } ... type Vehicle { id: ID! year: Int! make: String! model: Int! askingPrice: Float costBasis: Float @hasRole(role: “MANAGER”) numberOfOffers: Int @isAuthenticated } ``` At a glance, we know what is protected and what is not. In my book, that’s a win! 🍻 How do we get to such magic? You guessed it — [directive resolvers](https://www.apollographql.com/docs/graphql-tools/schema-directives.html#directiveResolvers-option). ### Realizing Directive Resolvers Into Permissions is Straightforward [#realizing-directive-resolvers-into-permissions-is-straightforward] You can think of directive resolvers as *resolver middleware*. An incoming request first hits the directive resolver. If it passes (i.e. `next()` is invoked), the request continues to the actual field resolver. Here’s how we check for an authorized role inside a directive resolver: ```js const directiveResolvers = { ..., hasRole: (next, source, {role}, ctx) => { const user = getUser() if (role === user.role) return next(); throw new Error(`Must have role: ${role}, you have role: ${user.role}`) }, ... } ``` Enforcing permission rules with GraphQL directives allows to remove any authorization logic from the field resolvers: ```js const Query = { vehicles: (parent, args, context, info) => context.db.query.vehicles({ where: { dealership: args.id } }), } ``` Note that setting up directiveResolvers with graphql-tools is straightforward: ```js export const schema = makeExecutableSchema({ typeDefs, resolvers, directiveResolvers, }) ``` ### Changing Directive Permissions Takes Little Work [#changing-directive-permissions-takes-little-work] Now, let’s change the requirements: * `numberOfOffers` should be restricted to *managers* (formerly just *authenticated*) * `askingPrice` should be restricted to *authenticated users* (formerly *unauthenticated*) Here, hold my beer… ```graphql type Vehicle { id: ID! year: Int! make: String! model: Int! askingPrice: Float @isAuthenticated costBasis: Float @hasRole(role: “MANAGER”) numberOfOffers: Int @hasRole(role: “MANAGER”) } ``` …Done! We can update our permissions simply by adjusting the directives in the schema definition, without touching the actual implementation. The generic directive resolvers take care of enforcing the rules. ### Demo: Experimenting With Directive Permissions [#demo-experimenting-with-directive-permissions] The best way to learn is experimentation, so I made a [Launchpad demo](https://launchpad.graphql.com/nxp1870jl7) to play around with permissions, queries, and users. For instance, try running this mutation as different users: ```graphql mutation { updateAskingPrice(id: "1", newPrice: 10000) { id year make model askingPrice } } ``` Change the directives on the schema to see how the permissions change. Note that Launchpad’s GraphiQL shows errors first, scroll down to see data. > I also made a [demo repo](https://github.com/LawJolla/prisma-auth0-example) combining Prisma, [Auth0](http://www.auth0.com), and directive permissions. ## Potential Drawbacks & Alternatives [#potential-drawbacks--alternatives] Some people argue against “polluting” the schema with information that goes beyond the actual GraphQL schema definition. I appreciate that argument. For a different approach that doesn’t touch your schema definition, check out [GraphQL Shield](https://github.com/maticzav/graphql-shield) by [Matic Zavadlal](https://twitter.com/maticzav). It even has a few ingenious tricks like caching permission functions per request. ## Directive Permissions Provide Clear and Easy Authorization [#directive-permissions-provide-clear-and-easy-authorization] Permissions in GraphQL can be difficult at first. With RESTful APIs, authorization is implemented by protecting the individual API endpoints. This approach does not work for GraphQL because there’s only a single endpoint exposed by the server. Therefore, authorization in GraphQL requires a major shift in thinking. The official GraphQL spec doesn’t provide any guidance and best practices for implementing permissions are still emerging. One of them being \*directive permissions \*which we covered in this article. To understand directive permissions, we first took at look at the cumbersome resolver implementation when going for a naive approach. We then learned about directive permissions and how they provide a declarative alternative by extending the GraphQL schema definition with dedicated GraphQL directives. I believe this emerging directive permissions pattern finally gives GraphQL a clear and declarative path to securing data. It does so by separating permissions and data into their respective layers with a concise and expressive syntax. > To get some practical experience with the examples explained in this article, check out the [live demo](https://launchpad.graphql.com/nxp1870jl7) on Launchpad or the code in [this](https://github.com/LawJolla/prisma-auth0-example) GitHub repository. *** I like blogging about new software patterns and intellectual property law. If we share those interests, please consider following me [here](https://medium.com/@dwalsh.sdlr) and on Twitter [@LawJolla](https://twitter.com/lawjolla).