Generic Authorization with GraphQL and Ruby

Thiago von Sydow
Impraise Tech and Design
3 min readJan 8, 2018

This article was extracted from a Ruby talk given in the Amsterdam.rb meetup. You can see the first article here.

The GraphQL gem provides us with field instrumentation, which is a good way to execute code around your GraphQL fields. That link shows how to do a simple timer to check how much time it took to resolve the field. But what if we could extend this idea to do more helpful and complex executions? This article will show 2 instrumentations we are using to handle authorization in our queries.

Authorize a single element

Imagine that are 2 organizations. We are a member of organization 1 but not organization 2. To retrieve the number of members from each of them, we use a query like this:

{
my_org: organization(id: 1) {
members {
totalCount
}
}

other_org: organization(id: 2) {
members {
totalCount
}
}
}

The output of the query might look like this:

{
“data”: {
“my_org”: {
“members”: {
“totalCount”: 9
}
},
“other_org”: null
},
“errors”: [
{
“message”: “forbidden”,
“path”: [
“other_org”
]
}
]
}

Since we can’t access other_org, the data for this organization is null. In addition there’s an error message pointing to that organization (following the GraphQL specification) . Here’s how we do it using field instrumentation.

  1. Create your instrumentation class:

2. In the schema, add a metadata definition and instrument your fields:

3. And use it!

Now, let’s see what’s going on here: in the first step, we replace the resolve proc of the field with a different one. This proc gets the result of the old definition, checks against a policy and raises an error if it’s not allowed. The policy_class is a regular Pundit policy.

In the second step, we configure the fields to accept the access_permission metadata, and add a line to the schema to configure the instrumentation. The metadata is the key piece here that allows us to make the code reusable.

In the third step, we have the line access_permission(policy_class: OrganizationsPolicy, action: :load?) which describes the Pundit policy class and which action it should use.

And that’s it! To apply this to other fields, we only need to add that one line and we’re all set.

Scoping down a collection of elements

In the previous query, we asked the total number of members in the organization. There are 9 members in total, but only 2 are members of our team. What if we want to restrict that count to only include members that belong to our team?

To achieve this, we’ll use the same principle as the previous instrumentation, but with one difference in the authorization_proc. It will use Pundit scopes to narrow down the query before returning a response.

  1. We’ll rewrite the authorization_proc to look like this:

2. The way to use it is the same, except that now we don’t need an action parameter.

Keep in mind that initial_scope must be a ActiveRecord::(Relation|Connection|other) (or Sequel::Dataset in our case) class so when it’s passed to Pundit it can add the proper WHERE clause that’ll filter the collection. A Scope class for our example would be:

Now the query returns only the 2 members of our team!

# Query{
my_org: organization(id: 1) {
members {
totalCount
}
}
}
# Result{
“data”: {
“my_org”: {
“members”: {
“totalCount”: 2
}
}
}
}

Looking forward

We are currently exploring new ways to use features from the GraphQL Ruby gem to simplify repeated tasks in creating the graph. For example, a presence metadata for adding “not found” errors.

Problem solved… ?

Are you using some component in a way that simplifies your workflow? Leave a comment!

--

--

Thiago von Sydow
Impraise Tech and Design

Developer at @impraise. Fascinated by technology and innovation.