Roles

The Sanity Roles system is a granular way of attaching specific capabilities to specific groups of users. It is designed to function in a structured and flexible way. The goal of the Roles system is to provide a set of strong default permissions groups with an API for creating, managing, and using custom roles built the way your organization works with content.

The Roles system is comprised of five main entities:

  • Grants
  • Resources
  • Permission Resource Schema
  • Roles
  • Users

Grants and Resources

A grant is the root item in the roles system. They represent the ability to perform a specific action or give access to a specific resource.

A resource defines an element of a Sanity project or organization on which a user can have special grants.

These permission pairs are defined in the related Permission Resource Schema. In addition, each grant may also have parameters, further limiting the scope of that permission.

Permission Resource Schema

A Permission Resource Schema (or simply "Permission") defines a set of possible actions that defines that can be performed on specific resources. These can be accessed via the /projects/${project_id}/permissionResourceSchemas endpoint. Each provides a template for use in creation of new roles and custom permissions.

Use cases

  • A grant to read and edit (but not publish) documents of blogPost on the production dataset
  • A grant to create project API tokens

Syntax

[
  {
    "id": "srp-bvl4pkml",
    "title": "Project Tokens",
    "description": "Manage authorization tokens for a project",
    "name": "sanity.project.tokens",
    "permissions": [
      {
        "name": "read",
        "title": "Read",
        "description": "Ability to read project tokens",
        "params": []
      },
      {
        "name": "create",
        "title": "Create",
        "description": "Ability to create project tokens",
        "params": []
      },
      {
        "name": "delete",
        "title": "Delete",
        "description": "Ability to delete project tokens",
        "params": []
      }
    ]
  },
  {
    "id": "srp-ysohuysj",
    "title": "Project CORS",
    "description": "Manage CORS settings for a project",
    "name": "sanity.project.cors",
    "permissions": [
      {
        "name": "read",
        "title": "Read",
        "description": "Ability to read project cors",
        "params": []
      },
      {
        "name": "create",
        "title": "Create",
        "description": "Ability to create project cors",
        "params": []
      },
      {
        "name": "delete",
        "title": "Delete",
        "description": "Ability to delete project cors",
        "params": []
      }
    ]
  },
  {
    "id": "srp-2ve36erw",
    "title": "Sanity Document Filter",
    "description": "Defines a permission resource for a filtered collection of Sanity documents",
    "name": "sanity.document.filter",
    "permissions": [
      {
        "name": "create",
        "title": "Create",
        "description": "Create documents matching the filter",
        "params": [
          {
            "name": "datasetPolicyId",
            "type": "string",
            "title": "Dataset Policy Id",
            "description": "A dataset policy id to scope the permission"
          }
        ]
      },
      {
        "name": "read",
        "title": "Read",
        "description": "Read documents matching the filter",
        "params": [
          {
            "name": "datasetPolicyId",
            "type": "string",
            "title": "Dataset Policy Id",
            "description": "A dataset policy id to scope the permission"
          }
        ]
      },
      {
        "name": "update",
        "title": "Update",
        "description": "View history for documents matching the filter",
        "params": [
          {
            "name": "datasetPolicyId",
            "type": "string",
            "title": "Dataset Policy Id",
            "description": "A dataset policy id to scope the permission"
          }
        ]
      },
      {
        "name": "manage",
        "title": "Manage",
        "description": "Manage documents matching the filter",
        "params": [
          {
            "name": "datasetPolicyId",
            "type": "string",
            "title": "Dataset Policy Id",
            "description": "A dataset policy id to scope the permission"
          }
        ]
      },
      {
        "name": "history",
        "title": "History",
        "description": "Read the history of documents matching the filter",
        "params": [
          {
            "name": "datasetPolicyId",
            "type": "string",
            "title": "Dataset Policy Id",
            "description": "A dataset policy id to scope the permission"
          }
        ]
      },
      {
        "name": "editHistory",
        "title": "Edit History",
        "description": "Edit the history of documents matching the filter",
        "params": [
          {
            "name": "datasetPolicyId",
            "type": "string",
            "title": "Dataset Policy Id",
            "description": "A dataset policy id to scope the permission"
          }
        ]
      }
    ]
  },
]

Role

Roles define a set of grants which users can have assigned to them. A user can have many roles and grants, even within the same organization.

Default Roles

By default, there are specifically defined roles for each plan type. Custom roles are available for Enterprise customers.

All plans

  • Administrator – Read and write access to all datasets, with full access to all project settings.
  • API Tokens
    • Editor Token (read+write)
    • Viewer Token (read-only)

Free forever

  • Administrator
  • Viewer – Can view all documents in all datasets within the project

Team

  • Administrator
  • Viewer

Business

  • Administrator
  • Editor
  • Contributor – Read and write access to draft content within all datasets, with no access to project settings.
  • Developer – Read and write access to all datasets, with access to project settings for developers.

User

A user is a person making use of a Sanity resource. A user always references the system via a role. A user is defined by an associated email but can also reference a "robot user" or token.

Creating a custom role

Enterprise Feature

Custom roles are included in Enterprise plans.

To create a custom role, you need to create a new role, create the grants for the role, and assign the role to individual users.

Create the role object

A custom role is an object containing a title, name, and description properties. In this example, a custom role with a name of custom-role, a title of My Custom Role, and a description of Custom role is created by sending that data to a given projects /roles API endpoint.

curl \
	-X POST \
	-H "Authorization: Bearer ${apiBearerToken}"
	-H "Content-Type: application/json"
	-d '{"title": "My Custom Role", "name": "custom-role", "description": "Custom role"}'
	https://api.sanity.io/v2021-06-07/projects/${projectId}/roles

This is now a custom role, but it currently has no granted permissions. To add permissions, you connect each permission to the role via the /grants API endpoint.

Inspecting and adding grants

To see the available permission resources for the current project, you can send a GET request to the /permissionResources API endpoint for the current project.

curl \
	-X GET \
	-H "Authorization: Bearer ${apiBearerToken}"
	https://api.sanity.io/v2021-06-07/projects/${projectId}/permissionResources

Once you select the resources from this list you wish to add to the role, you can send a POST request to the /grants endpoint for the project for each addition.

curl \
	-X POST
	-H "Authorization: Bearer ${apiBearerToken}"
	-H "Content-Type: application/json"
	-d '{"roleName": "custom-role", "permissionName": "${permissionName}", "permissionResourceId": "${permissionResourceName}"}'
	https://api.sanity.io/v2021-06-07/projects/${projectId}/grants

Creating a custom permission resource

Enterprise Feature

Custom roles are included in Enterprise plans.

The above examples create a new role using pre-made permission resources. However, when you need to create granular permissions for specific roles, you can create a custom permission resource.

For Sanity to understand your resource, you need to have it correspond to a specific permission resource schema. You can see all the schema by sending a GET request to the /projects/${projectId}/permissionResourceSchemas endpoint. These function much like a configurable template for your custom permission.

To create a custom resource around a specific set of documents, you can use the sanity.document.filter schema. This schema provides a config option for adding a GROQ filter to specify a specific set of documents. The permissions array gives you the name of all the permissions that Sanity will understand with this template (e.g. "update," "read," etc.).

{
  "id": "srp-2ve36erw",
  "title": "Sanity Document Filter",
  "description": "Defines a permission resource for a filtered collection of Sanity documents",
  "name": "sanity.document.filter",
  "config": [
    {
      "name": "filter",
      "type": "string",
      "title": "Filter",
      "description": "GROQ filter limiting the document collection"
    }
  ],
  "permissions": [
    {
      "name": "update",
      "title": "Update",
      "description": "View history for documents matching the filter",
      "params": [
        {
          "name": "datasetPolicyName",
          "type": "string",
          "title": "Dataset Policy Name",
          "description": "A dataset policy name to scope the permission",
          "defaultValue": "default"
        }
      ]
    },
    {
      "name": "read",
      "title": "Read",
      "description": "Read documents matching the filter",
      "params": [
        {
          "name": "datasetPolicyName",
          "type": "string",
          "title": "Dataset Policy Name",
          "description": "A dataset policy name to scope the permission",
          "defaultValue": "default"
        }
      ]
    },
    {
      "name": "manage",
      "title": "Manage",
      "description": "Manage documents matching the filter",
      "params": [
        {
          "name": "datasetPolicyName",
          "type": "string",
          "title": "Dataset Policy Name",
          "description": "A dataset policy name to scope the permission",
          "defaultValue": "default"
        }
      ]
    },
    {
      "name": "history",
      "title": "History",
      "description": "Read the history of documents matching the filter",
      "params": [
        {
          "name": "datasetPolicyName",
          "type": "string",
          "title": "Dataset Policy Name",
          "description": "A dataset policy name to scope the permission",
          "defaultValue": "default"
        }
      ]
    },
    {
      "name": "create",
      "title": "Create",
      "description": "Create documents matching the filter",
      "params": [
        {
          "name": "datasetPolicyName",
          "type": "string",
          "title": "Dataset Policy Name",
          "description": "A dataset policy name to scope the permission",
          "defaultValue": "default"
        }
      ]
    }
  ]

To create the resource, you need to pass an object containing its details to the /permissionResources endpoint.

curl \
	-X POST
	-H "Authorization: Bearer ${apiBearerToken}"
	-H "Content-Type: application/json"
	-d '{"permissionResourceType": "sanity.document.filter", "title": "Awesome Documents!", "description": "Our awesome documents", "config": {"filter": "_type == \"awesome\""}}'
	https://api.sanity.io/v2021-06-07/projects/${projectId}/permissionResources

When the permission resource is created, an id will be returned. This ID can be used to create a grant based on this resource. Just like in the above examples, only one grant will be created at a time.

# Create read grant for custom-role
curl \
	-X POST
	-H "Authorization: Bearer ${apiBearerToken}"
	-H "Content-Type: application/json"
	-d '{"roleName": "custom-role", "permissionName": "read", "permissionResourceId": "${idReturned}"}'
	https://api.sanity.io/v2021-06-07/projects/${projectId}/grants

	
# Create Update grant for custom-role
curl \
	-X POST
	-H "Authorization: Bearer ${apiBearerToken}"
	-H "Content-Type: application/json"
	-d '{"roleName": "custom-role", "permissionName": "update", "permissionResourceId": "${idReturned}"}'
	https://api.sanity.io/v2021-06-07/projects/${projectId}/grants

At this point, any user with the custom role will have this specific set of permissions around documents of a _type == "awesome".

All permissions by default role

The following are the granular permission grants for the default roles provided by various plans. You can view your default permission resources by sending a GET request to a project's /roles endpoint.

[
  {
    "name": "administrator",
    "title": "Administrator",
    "description": "Administrate projects",
    "isCustom": false,
    "projectId": "xxxxxx",
    "appliesToUsers": true,
    "appliesToRobots": false,
    "grants": {
      "sanity.document.filter.mode": [
        {
          "grants": [
            {
              "name": "mode",
              "params": {
                "mode": "publish",
                "history": true,
                "datasetPolicyName": "default"
              }
            }
          ],
          "config": {
            "filter": "_id in path(\"**\")"
          }
        }
      ],
      "sanity.project": [
        {
          "grants": [
            {
              "name": "createSession",
              "params": {}
            },
            {
              "name": "delete",
              "params": {}
            },
            {
              "name": "deployStudio",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            },
            {
              "name": "update",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.cors": [
        {
          "grants": [
            {
              "name": "create",
              "params": {}
            },
            {
              "name": "delete",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.datasets": [
        {
          "grants": [
            {
              "name": "create",
              "params": {}
            },
            {
              "name": "delete",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            },
            {
              "name": "update",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.graphql": [
        {
          "grants": [
            {
              "name": "manage",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.members": [
        {
          "grants": [
            {
              "name": "delete",
              "params": {}
            },
            {
              "name": "invite",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            },
            {
              "name": "update",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.roles": [
        {
          "grants": [
            {
              "name": "create",
              "params": {}
            },
            {
              "name": "delete",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            },
            {
              "name": "update",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.tokens": [
        {
          "grants": [
            {
              "name": "create",
              "params": {}
            },
            {
              "name": "delete",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.usage": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.webhooks": [
        {
          "grants": [
            {
              "name": "create",
              "params": {}
            },
            {
              "name": "delete",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ]
    }
  },
  {
    "name": "contributor",
    "title": "Contributor",
    "description": "Read and write to select datasets within the project",
    "isCustom": false,
    "projectId": "xxxxxx",
    "appliesToUsers": true,
    "appliesToRobots": true,
    "grants": {
      "sanity.document.filter.mode": [
        {
          "grants": [
            {
              "name": "mode",
              "params": {
                "mode": "create",
                "history": true,
                "datasetPolicyName": "default"
              }
            }
          ],
          "config": {
            "filter": "_id in path(\"**\")"
          }
        }
      ],
      "sanity.project.members": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.roles": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ]
    }
  },
  {
    "name": "create-session",
    "title": "Create Session",
    "description": "Create third-party sessions, manage third-party user profiles",
    "isCustom": false,
    "projectId": "xxxxxx",
    "appliesToUsers": false,
    "appliesToRobots": true,
    "grants": {
      "sanity.document.filter": [
        {
          "grants": [
            {
              "name": "create",
              "params": {
                "datasetPolicyName": "default"
              }
            },
            {
              "name": "history",
              "params": {
                "datasetPolicyName": "default"
              }
            },
            {
              "name": "manage",
              "params": {
                "datasetPolicyName": "default"
              }
            },
            {
              "name": "read",
              "params": {
                "datasetPolicyName": "default"
              }
            },
            {
              "name": "update",
              "params": {
                "datasetPolicyName": "default"
              }
            }
          ],
          "config": {
            "filter": "!(_id in [\"_.groups.create-session\", \"_.groups.administrator\", \"_.groups.write\", \"_.groups.read\", \"_.groups.public\"] || _id in path(\"_.groups.sanity.**\")) && _id in path(\"**\")"
          }
        }
      ],
      "sanity.project": [
        {
          "grants": [
            {
              "name": "createSession",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.members": [
        {
          "grants": [
            {
              "name": "update",
              "params": {}
            }
          ],
          "config": {}
        }
      ]
    }
  },
  {
    "name": "deploy-studio",
    "title": "Deploy Studio",
    "description": "A role that is only allowed to deploy the studio",
    "isCustom": false,
    "projectId": "xxxxxx",
    "appliesToUsers": false,
    "appliesToRobots": true,
    "grants": {
      "sanity.project": [
        {
          "grants": [
            {
              "name": "deployStudio",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.graphql": [
        {
          "grants": [
            {
              "name": "manage",
              "params": {}
            }
          ],
          "config": {}
        }
      ]
    }
  },
  {
    "name": "developer",
    "title": "Developer",
    "description": "Develop the projects",
    "isCustom": false,
    "projectId": "xxxxxx",
    "appliesToUsers": true,
    "appliesToRobots": true,
    "grants": {
      "sanity.document.filter.mode": [
        {
          "grants": [
            {
              "name": "mode",
              "params": {
                "mode": "publish",
                "history": true,
                "datasetPolicyName": "default"
              }
            }
          ],
          "config": {
            "filter": "_id in path(\"**\")"
          }
        }
      ],
      "sanity.project": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.cors": [
        {
          "grants": [
            {
              "name": "create",
              "params": {}
            },
            {
              "name": "delete",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.datasets": [
        {
          "grants": [
            {
              "name": "create",
              "params": {}
            },
            {
              "name": "delete",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            },
            {
              "name": "update",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.graphql": [
        {
          "grants": [
            {
              "name": "manage",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.members": [
        {
          "grants": [
            {
              "name": "invite",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.roles": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.tokens": [
        {
          "grants": [
            {
              "name": "create",
              "params": {}
            },
            {
              "name": "delete",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.usage": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.webhooks": [
        {
          "grants": [
            {
              "name": "create",
              "params": {}
            },
            {
              "name": "delete",
              "params": {}
            },
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ]
    }
  },
  {
    "name": "editor",
    "title": "Editor",
    "description": "Editor can make changes to all datasets within the project",
    "isCustom": false,
    "projectId": "xxxxxx",
    "appliesToUsers": true,
    "appliesToRobots": true,
    "grants": {
      "sanity.document.filter.mode": [
        {
          "grants": [
            {
              "name": "mode",
              "params": {
                "mode": "publish",
                "history": true,
                "datasetPolicyName": "default"
              }
            }
          ],
          "config": {
            "filter": "_id in path(\"**\")"
          }
        }
      ],
      "sanity.project": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.datasets": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.members": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.roles": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.usage": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ]
    }
  },
  {
    "name": "viewer",
    "title": "Viewer",
    "description": "Viewer can view all documents in all datasets within the project",
    "isCustom": false,
    "projectId": "xxxxxx",
    "appliesToUsers": true,
    "appliesToRobots": true,
    "grants": {
      "sanity.document.filter.mode": [
        {
          "grants": [
            {
              "name": "mode",
              "params": {
                "mode": "read",
                "history": true,
                "datasetPolicyName": "default"
              }
            }
          ],
          "config": {
            "filter": "_id in path(\"**\")"
          }
        }
      ],
      "sanity.project": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.datasets": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.members": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.roles": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ],
      "sanity.project.usage": [
        {
          "grants": [
            {
              "name": "read",
              "params": {}
            }
          ],
          "config": {}
        }
      ]
    }
  }
]

Was this article helpful?