How to implement viewerCanSee in GraphQL

Improving security on GraphQL, what we do at Brand Lovers

Sibelius Seraphini
Entria
2 min readNov 12, 2016

--

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:

GraphiQL interface

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

Newsletter

Subscribe to my newsletter for new content https://sibelius.substack.com/

--

--