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 graphcool repository and navigate to this directory or download only this example with the following command:
curl https://codeload.github.com/graphcool/graphcool/tar.gz/master | tar -xz --strip=2 graphcool-master/examples/permissions
cd permissions
Next, 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 graphcool@next
You 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 service
When prompted which cluster you'd like to deploy, chose any of Backend-as-a-Service
-options (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 deploy
again 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 info
From 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: "[email protected]"
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 User
s 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 fieldsdescription
andimageUrl
on nodes of typePost
Post.create
: Only authenticated users can create nodes of typePost
Post.update
: To update a node of typePost
, aUser
must be:- authenticated
- the
author
of thePost
(see the permission queryUpdatePost
insrc/permissions/Post.graphql
)
Post.delete
: To delete a node of typePost
, aUser
must be:- authenticated
- either the
author
of thePost
or anADMIN
(see the permission queryDeletePost
insrc/permissions/Post.graphql
)
User.read
: Everyone can the fieldsemail
andposts
read nodes of typeUser
User.create
:User
nodes can only be created with a root token (see the code for thesignup
function)User.update
: To update the fieldsemail
,password
andposts
on a node of typeUser
, aUser
must be:- authenticated
- either the "owner" of the
User
or anADMIN
(see the permission queryUpdateUserData
insrc/permissions/.graphql
)
User.update
: To update the fieldrole
on a node of typeUser
, aUser
must be:- authenticated
- an
ADMIN
(see the permission queryUpdateUserRole
insrc/permissions/User.graphql
)
User.delete
: To delete a node of typeUser
, aUser
must be:- authenticated
- either the "owner" of the
User
or anADMIN
(see the permission queryDeleteUser
insrc/permissions/deleteUser.graphql
)
UsersPosts.connect
: To connect aPost
node with aUser
node via theUserPosts
relation, aUser
must be authenticatedUsersPosts.disconnect
: To disconnect aPost
node from aUser
node in theUserPosts
relation, aUser
must 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
.