👀 Our most exciting product launch yet 🚀 Join us May 8th for Sanity Connect

Access Control

Specifying who can access your data

Gotcha

Custom access control has been deprecated in favor of the creation of custom roles.


Sanity has preliminary access control for users and groups. Currently, every dataset is automatically populated with the following fixed groups:

  • Administrator: can create, update, delete, and read all documents
  • Read+Write: can create, update, delete, and read all documents
  • Read: can read documents, but only under the root path (so studio drafts and system documents are hidden)
  • Create Session: can create Sanity tokens and additional custom groups if you are using third-party login (available as an add-on to Enterprise plans).

Unauthenticated users get the special identity everyone, and are automatically members of the read group.

Group memberships and user invitations are managed in the project's management console.

Gotcha

All documents published in the Studio in a public dataset are publicly available, since the everyone user has read-access to all documents under the root path. The only way to hide these are to set the dataset as private and add custom permissions for everyone. Studio drafts are only available to authenticated users in the read+write or administrator groups, since they are stored under the drafts. path.

Custom access control

Paid feature

Custom access control is an enterprise plan feature.

If you have enabled custom access control on your project’s plan, you can add and modify groups to set up custom access control rules. Groups are stored as regular Sanity documents in each dataset (see details below), and can be modified using mutations like any other document. Only create session tokens have the permission to create new and update group documents. The built-in group documents can't be changed, these are the group documents with the _id:

  • _.groups.administrator
  • _.groups.create-session
  • _.groups.public
  • _.groups.read
  • _.groups.write

Group documents

Groups are stored as documents of type system.group under the _.groups. path, and look something like this:

{
  "_id": "_.groups.read",
  "_type": "system.group",
  "_rev": "wzDKrHcEddnCsDSCdb6KHZ",
  "_createdAt": "2017-12-12T11:46:55Z",
  "_updatedAt": "2017-12-12T11:46:55Z",
  "grants": [
    {
      "path": "*",
      "permissions": ["read"]
    }
  ],
  "members": ["everyone"]
}

Gotcha

Custom group documents can only be created and modified by the "Create Session" role. You may create a token with this role from the project management console under Settings, API.

grants is an array giving a set of permissions (read, create, update, or manage) for documents either matching a path expression given in path, or an filter expression given in filter.

{
  "_id": "_.groups.authors",
  "_type": "system.group",
  "_rev": "wzDKrHcEddnCsDSCdb6KHZ",
  "_createdAt": "2017-12-12T11:46:55Z",
  "_updatedAt": "2017-12-12T11:46:55Z",
  "grants": [
    {
      "filter": "_type == 'categories'",
      "permissions": ["read", "create"]
    },
    {
      "filter": "_type == 'post'",
      "permissions": ["read", "update", "create"]
    }
  ],
  "members": ["e-a-user-id", "e-another-user-id"]
}

Gotcha

Permissions by filter can't include subqueries or joins. For example, "filter": "_type == 'post' && (author._ref in *[_type == 'authors'])" will not work.

Permissions are additive, such that any grant giving a permission to a matching document is sufficient for access.

members lists the IDs of the group's members, where everyone is the special ID given to unauthenticated users. Member IDs can only contain the characters a-zA-Z0-9_-.

The default system.group documents cannot be modified through the API, use the project's management console instead.

If you want to limit the scope of everyone, you'll have to set your dataset to private, and add an additional group with everyone as a member and the grants you want them to have.

Setting permissions based on document IDs

Sometimes it's useful to grant or restrict access to certain documents. In these cases the grants filter can include a check against the document _id like any other id. Make sure to include the draft id too:

{
 "filter": "_id == 'some-document-id' || _id == 'drafts.some-document-id'",
 "permissions": ["read", "update", "create"],
 "members": ["e-a-user-id"]
}

Was this article helpful?