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.
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
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.
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"]
}