This example demonstrates how to configure permission rules for your application, in combination with an email-password based authentication workflow. It contains the service definition for a simple "Instagram"-app where users can share posts with their friends.
The focus of this example is explaining how the Graphcool permission system works. If you're looking for a dedicated authentication example, check out the auth directory.
This is the data model for the application (defined in types.graphql):
enum Role {
ADMIN
CUSTOMER
}
type User @model {
id: ID! @isUnique
role: Role!
posts: [Post!]! @relation(name: "UserPosts")
email: String @isUnique
password: String
}
type Post @model {
id: ID! @isUnique
description: String!
imageUrl: String!
author: User! @relation(name: "UserPosts")
}Here is an overview of the file structure in this example:
.
├── README.md
├── graphcool.yml
├── node_modules
├── package.json
├── src
│ ├── email-password
│ │ ├── authenticate.graphql
│ │ ├── authenticate.js
│ │ ├── loggedInUser.graphql
│ │ ├── loggedInUser.js
│ │ ├── signup.graphql
│ │ ├── signup.js
│ │ └── signup.ts
│ └── permissions
│ ├── Post.graphql
│ └── User.graphql
├── types.graphql
└── yarn.lock
Clone the full framework repository and navigate to this directory or download only this example with the following command:
curl https://codeload.github.com/graphcool/framework/tar.gz/master | tar -xz --strip=2 framework-master/examples/permissions
cd permissionsNext, you need to create your GraphQL server using the Graphcool CLI.
If you haven't already, go ahead and install the CLI first:
npm install -g graphcoolYou can now deploy the Graphcool service that's defined in this directory. Before that, you need to install the node dependencies for the defined functions:
yarn install # install dependencies
graphcool deploy # deploy serviceWhen prompted which cluster you'd like to deploy, chose any of the Shared Clusters (shared-eu-west-1, shared-ap-northeast-1 or shared-us-west-2) rather than local.
Note: Whenever you make changes to files in this directory, you need to invoke
graphcool deployagain to make sure your changes get applied to the "remote" service.
That's it, the service is now deployed and you can start sending queries and mutation to its API 🎉
The easiest way to test the deployed service is by using a GraphQL Playground.
You can open by pasting the HTTP endpoint for the GraphQL API into the address bar of a browser. To get access to the endpoint, use the following command in the terminal:
graphcool infoFrom the printed endpoints, chose the one for the Simple API and paste it into the address bar of your browser.
Note: You can not properly verify permission rules inside the standalone Playground app, since it gives you root access to all API operations.
You can send the following mutation in the Playground to create a new User node and at the same time retrieve an authentication token for it:
mutation {
signupUser(
email: "alice@graph.cool"
password: "graphql"
role: CUSTOMER
) {
id
token
}
}To authenticate requests that you're sending through the Playground, you need to set the token you just received as the Authorization HTTP header. You can do so in the bottom-left corner of the Playground:
See below for a list of all permission rules configured for this service. Here are instructions to test a few of them:
Only authenticated Users are able to create Posts (see the rule).
Send the following mutation to test the permission, without having the HTTP Authorization header set:
mutation {
createPost(
description: "Great sunset"
imageUrl: "http://example.org/sunset.png"
authorId: "__AUTHOR_ID__" # replace with the `id` of the `User` you created before
) {
id
}
}This will return an error with the following message: "Insufficient permissions for this mutation".
When setting the HTTP Authorization header as described above, the same mutation will create a new Post node.
To delete a node of type Post, a User must be authenticated and either the author of the Post or an ADMIN (see the rule):
mutation {
deletePost(
id: "__POST_ID__" # replace with the `id` of the `Post` you created before
) {
id
}
}This mutation will only work if the User that's sending the request (i.e. who the token in the Authorization HTTP header belongs to) is the author of the Post to be deleted, or if it's an ADMIN.
Here's a list of all permission rules that are configured for this service:
Post.read: Everyone can read the fieldsdescriptionandimageUrlon nodes of typePostPost.create: Only authenticated users can create nodes of typePostPost.update: To update a node of typePost, aUsermust be:- authenticated
- the
authorof thePost(see the permission queryUpdatePostinsrc/permissions/Post.graphql)
Post.delete: To delete a node of typePost, aUsermust be:- authenticated
- either the
authorof thePostor anADMIN(see the permission queryDeletePostinsrc/permissions/Post.graphql)
User.read: Everyone can the fieldsemailandpostsread nodes of typeUserUser.create:Usernodes can only be created with a root token (see the code for thesignupfunction)User.update: To update the fieldsemail,passwordandpostson a node of typeUser, aUsermust be:- authenticated
- either the "owner" of the
Useror anADMIN(see the permission queryUpdateUserDatainsrc/permissions/.graphql)
User.update: To update the fieldroleon a node of typeUser, aUsermust be:- authenticated
- an
ADMIN(see the permission queryUpdateUserRoleinsrc/permissions/User.graphql)
User.delete: To delete a node of typeUser, aUsermust be:- authenticated
- either the "owner" of the
Useror anADMIN(see the permission queryDeleteUserinsrc/permissions/deleteUser.graphql)
UsersPosts.connect: To connect aPostnode with aUsernode via theUserPostsrelation, aUsermust be authenticatedUsersPosts.disconnect: To disconnect aPostnode from aUsernode in theUserPostsrelation, aUsermust be authenticated
Graphcool uses the concept of permission queries to configure permission rules for a service.
Permission queries are special GraphQL queries that only return true or false (it's thus unnecessary to specify the selection set of the query when writing it).
Before an operation (e.g. Post.create) is performed against the GraphQL API of a Graphcool service, Graphcool will check the permission rules for that operation specified in graphcool.yml. If the permission rules reference one or more permission queries, Graphcool will first execute these permission queries. The requested operation will only be performed if all permission queries return true.
