I’m attempting to restrict certain fields on my User collection based on the current user’s role, but I’m currently at a loss on how to do so. My current thought is to setup two different types in my schema, one for non-admins and another for admins, and check authorization in the resolver. Is there a better way to do this?
Don’t do it in the resolver, do it in your own code (eg. what Apollo calls a connector). FB’s GraphQL best practices guide explains: http://graphql.org/learn/authorization/
Thanks. That’s exactly what I was wanting to know with where to do it. Is there anything out there on restricting certain fields?
Are somethere examples, tutorials, articles, tips about this??? Lack of information…
Looking at the source code for Vulcan (https://github.com/VulcanJS/Vulcan), the next evolution of Telescope, it looks like they are abstracting the field-level security into collection helpers. When defining a schema, a Vulcan schema object is passed through a function which builds the GraphQL schema and also adds the business logic to the app. Pretty cool approach IMO. Maybe @sacha can add some insight?
Check out these files for further info:
The basic idea of what Vulcan does is that when someone asks for, say, a list of posts, the server restricts the database query’s
field option based on who the current user is. In Vulcan, the function that does this is called
As you can see it iterates over the collection schema, because that’s where permissions are stored in Vulcan. But you could just as well have a hard-coded list of field names for each user role.
As for where to call this from, in Vulcan we call it from the resolvers directly, but @rahul is right that having an additional connector layer can be a good idea. It’s more of an architecture thing though, it doesn’t actually change what code gets run.
In any case, in Vulcan all this happens completely independently from the GraphQL schema, which doesn’t know or care at all about permissions.
Thanks for that clarity, @sacha. Really enjoying what I’ve seen in Vulcan so far.
Actually I have to amend that slightly, I’ve started using Dataloader so I’m now doing things a bit different. Instead of using the
fields specifier, I always get all fields from Mongo (so no
fields option), and then manually loop over documents removing any disallowed fields.
It’s more work, but the advantage is that the logic is the same whether the document (or documents) are coming from Mongo, the Dataloader cache, or any future other data source.
Another approach is to use authorization library like CASL https://github.com/stalniy/casl and function composition to protect your resolvers. This will allow not to mix business and authorization logic (Single Responsibility - should only 1 reason to change the class, function, entity, etc)
Another approach (one that we’re using right now): https://about.sourcegraph.com/graphql/handling-authentication-and-authorization-in-graphql/
We have a
getScopes on each model that returns which scopes the current user has. Then in the type, we define the scope required to view each field. So far, it’s been really nice having this logic in the graphQL layer instead of at the db layer (or somewhere else).