How to implement viewerCanSee in GraphQL

Improving security on GraphQL, what we do at Brand Lovers

Sibelius Seraphini
Nov 12, 2016 · 2 min read

So, what is viewerCanSee ?

ViewerCanSee is a function that determine whether the current viewer (logged user) can see a given data in GraphQL. Example: viewer can only see his own credit cards:

function viewerCanSee(viewer, creditCard) {
return creditCard.user === viewer;
}

One problem that we faced using only this approach is that sometimes the viewer can see part of the model, and only using this function is not enough. For instance, viewer can see another user name but he cannot see another user email, but he can see his own email.

To organize better my models and DataLoader code, we created a class to load each model. This class has a viewerCanSee method that decides if the viewer can see the current data, and we also have a constructor that let us determine which fields the current viewer can see.

Below is an example of UserLoader class that restrict email and active fields of User.

export default class User {
static userLoader = new DataLoader(
ids => Promise.all(ids.map((id) => UserModel.findOne({ _id: id })))
);

constructor(data, viewer) {
this.id = data.id;
this._id = data._id;
this.name = data.name;

// you can only see your own email, and your active status
if (viewer && viewer._id.equals(data._id)) {
this.email = data.email;
this.active = data.active;
}
}

static viewerCanSee(viewer, data) {
// Anyone can se another user
return true;
}

static async load(viewer, id) {
if (!id) return null;

const data = await User.userLoader.load(id);

if (!data) return null;

return User.viewerCanSee(viewer, data) ? new User(data, viewer) : null;
}
}

The final result it is in this PR https://github.com/sibelius/graphql-dataloader-boilerplate/pull/8, there is also a test to make sure that this implementation is correct


How to improve security on GraphQL

There are a lot of concern about security when using a GraphQL server

You can use GraphiQL App (https://github.com/skevy/graphiql-app) to inspect any GraphQL URL, giving you all the available queries and mutations that you could do against that server. The image below is an example of how it look like:

This is possible because GraphQL provides introspection capabilities, and to limit the introspection capability will be addressed in this issue: https://github.com/graphql/graphql-js/issues/113.

While this does not land, you need to have different schemas for different users if you think this is a problem for your application. You could have a GraphQL for non authorized users, and another one that only for authorized ones.


If you would like to learn how to test a GraphQL server using Jest — read this post: https://medium.com/@sibelius/testing-a-graphql-server-using-jest-4e00d0e4980e#.9ilqyejfv

Thanks to https://github.com/plraphael and https://github.com/lucasbento to help me improving this idea

Entria

The Bleeding Edge Tech Team

Sibelius Seraphini

Written by

Technical Lead / FullStack Developer at Entria

Entria

Entria

The Bleeding Edge Tech Team

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade