fbpx logo-new mail facebook Dribble Social Icon Linkedin Social Icon Twitter Social Icon Github Social Icon Instagram Social Icon Arrow_element diagonal-decor rectangle-decor search arrow circle-flat
Development

Authorization in Ruby on Rails Relay-Compatible GraphQL API

Jason Haruska Tandem Alum

last updated May 23, 2017

For the past year, Tandem engineers have been shifting our web and mobile development stack to React.js/native backed by a GraphQL endpoint written in Ruby on Rails. We use the Relay framework for our components to manage communication with the graph. This has worked surprisingly well in a wide variety of projects. However, our pattern of using Pundit or CanCanCan for authorization of user requests had to be updated in our Rails app to reflect the new single-endpoint nature of the web server.

The GraphQL Relay Specification is actually pretty simple. There is an interface Node that has a globally unique ID. Graph types can implement that interface. If they do, Relay can query the Graph for that Node by ID without traversing the graph.

The issue we’re trying to solve is for a public graph that contains data the user must be authorized to access. The graphql-ruby gem provides helpers for implementing the Relay interface. We also need our top-level Viewer field to complete the root of the graph. Our Query root ends up looking something like this:

https://gist.github.com/haruska/485688f010f7a4c87c956a697aaa3513

With this graph definition, all authorization can be done at the node level. As you traverse the graph, the resolve code blocks can check the current user’s authorization before yielding sensitive data. For example, on an open source project I use CanCanCan and populate the graph context with both a current user and ability in the GraphqlController.

https://gist.github.com/haruska/0add8941b825b5a227c2ee1efd49dcbf

I can then use the ability to populate the graph. For reference, here is the ViewerType on the project. Note the resolve block filters the list of objects based on the ability:

https://gist.github.com/haruska/6241a29d1a8a740f4f99b23578ebfc56

Now, the rest of the graph is properly using the authorization ruleset to expose the correct data to each user. The last step is using the ability for a Node by ID. This was a bit trickier. The gem helper for the node field does take in a resolve block but you need to take care that the block is resolved to the helper. Here is the authorized QueryType root:

https://gist.github.com/haruska/7e3e0b7ff5d58532eb422d2e2325819c

Now the node and nodes fields both take the current ability into account when resolving the object.

Let’s do something great together

We do our best work in close collaboration with our clients. Let’s find some time for you to chat with a member of our team.

Say Hi