Your users
Permissions
Who may do what in your service, by role: rules with a path, a method and a priority, plus filters that limit a user to their own documents.
A permission says what a role may do: which paths, which methods, and optionally which documents. Every request to your service is checked against them on the server, where the client cannot bypass them. Permissions are documents in the acl collection, managed under Permissions.
How a request is checked
Every request is checked against the permissions in the acl collection:
-
Only the permissions for the user’s roles count.
-
They are tried in descending
priorityorder: higher numbers are evaluated first. -
The first one whose
predicatematches the request (path, method, query string and so on) allows it, and itsmongooptions apply. -
If none matches, the request is refused.
The path on Enterprise
| Plan | ACL collection path |
|---|---|
Free, Starter and Pro |
|
Enterprise |
|
In the console the page is always Permissions, whatever the plan.
A permission document
{
"_id": "usersCanReadOrders",
"roles": ["user"],
"predicate": "path-prefix('/orders') and method('GET')",
"priority": 100,
"mongo": {
"readFilter": { "owner": "@user._id" },
"writeFilter": null,
"mergeRequest": null,
"projectResponse": null
}
}
| Field | Required | Description |
|---|---|---|
|
Yes |
A unique name for the permission. Make it say what it does, such as |
|
Yes |
The role names the permission applies to. A user who holds at least one of them is covered. Roles are set on each user, on the Users page. |
|
Yes |
The condition a request must meet for the permission to match. See the predicate language below. |
|
Yes |
The evaluation order. Higher values are evaluated first, so give the more specific permissions the higher numbers. |
|
No |
Filters and changes applied to the data the request reads or writes. See below. |
|
No |
Only on a permission for |
The list
The page lists the permissions with their roles, predicate and priority, a page at a time.
Filter and sort
Type a MongoDB query in the Filter field, for example:
{ "roles": "user" }
or
{ "priority": { "$lt": 50 } }
The Sort field takes a sort document, such as {"priority": -1}.
Add a permission
-
Click Add permission.
-
Fill in the form fields:
-
Permission ID (
_id): a unique name. -
Roles: one or more role names, separated by commas.
-
Predicate: which requests it is about (see below). The console checks it as you type.
-
Priority: higher numbers are evaluated first.
-
MongoDB permissions: optionally,
readFilter,writeFilter,mergeRequestandprojectResponse, as JSON. -
API key issuance: optionally, the
apiKeysblock of a permission on/keys. See API keys.
-
-
Click Create permission. The console sends
POST /aclwith the document.
Edit a permission
-
Click Edit on a permission. The form opens in place.
-
Change any field except the ID.
-
Click Save. The console sends
PUT /acl/<id>with the whole document.
Delete a permission
Click Delete on a permission and confirm. The console sends DELETE /acl/<id>.
|
Warning
|
A deleted permission stops working within 20 seconds, the time any change to a permission takes to apply. Users whose access relied on it alone are refused from then on. |
The predicate language
A predicate is a condition on the request, written in the Undertow predicate language. These are the ones you will use most:
Paths
| Predicate | Description | Example |
|---|---|---|
|
Matches the exact request path. |
|
|
Matches any path that starts with the given prefix. |
|
|
Matches a path with variable segments. Refer to a captured segment later in the predicate as |
|
|
Matches paths ending with the given suffix. |
|
|
Matches the path against a regular expression. |
|
Methods
| Predicate | Example |
|---|---|
|
|
|
|
|
Combining them
Combine predicates with and, or and not:
path-prefix('/orders') and method('GET')
path-prefix('/reports') and (method('GET') or method('POST'))
path-prefix('/admin') and not method('GET')
Common predicates
| Goal | Predicate |
|---|---|
Allow GET on any path |
|
Allow all methods on |
|
Allow POST only to |
|
Allow GET and PATCH on |
|
Allow everything under |
|
Allow every method except DELETE, on every path |
|
Allow a user to edit only their own document |
|
… and only one field of it |
|
The @user.sub branch above covers users authenticating with a JWT, who carry the account id in the sub claim. bson-request-whitelist takes one or more comma-separated keys, dotted for nested ones (bson-request-whitelist(profile.name, profile.surname)), and checks the request body as the client sent it, before any mergeRequest adds to it.
|
Tip
|
The Predicate reference panel at the bottom of the Permissions page lists the predicates, and the help icon beside the Predicate field opens this section. |
Limit what a user sees and writes
The optional mongo object acts on the data. It applies to every request the permission allows, and the client does not see it.
readFilter
A MongoDB filter added to every read (GET). The client sees only the documents that match it, whatever filter it sends.
Each user sees only their own documents:
{
"mongo": {
"readFilter": { "owner": "@user._id" }
}
}
@user._id is replaced with the _id of the user making the request.
writeFilter
A MongoDB filter applied to every write (PUT, PATCH, DELETE). A write reaches only the documents that match it, and nothing tells the client.
Users cannot change other users' documents:
{
"mongo": {
"writeFilter": { "owner": "@user._id" }
}
}
mergeRequest
A document merged into the body of every write before it is stored. Use it for fields the server sets and the client cannot forge.
A new document is stamped with its owner:
{
"mongo": {
"mergeRequest": { "owner": "@user._id" }
}
}
Write sub-documents as nested objects, without dotted keys. MongoDB rejects a merged request that touches both a field and a path inside it, with ConflictingUpdateOperators.
Update operators in mergeRequest
Plain fields are merged into $set. A MongoDB update operator can be merged too, written with a leading underscore because a key starting with $ cannot be stored in a document. _$push becomes $push when the request is merged.
Append to a history the server controls, which the client cannot overwrite:
{
"mongo": {
"mergeRequest": {
"lastSeenAt": "@now",
"_$push": { "auditTrail": { "at": "@now", "by": "@user._id" } }
}
}
}
The client sends the field only to satisfy whatever bson-request-whitelist the predicate carries; the value it sends for a key that an array operator manages is discarded, so the two cannot conflict.
projectResponse
A MongoDB projection applied to every document in the response. Use it to hide sensitive fields.
Hide sensitive fields:
{
"mongo": {
"projectResponse": { "passwordHash": 0, "internalNotes": 0 }
}
}
Variables you can use
| Variable | Value at runtime |
|---|---|
|
The |
|
The |
|
The current instant, as a BSON date. In a JSON Schema, declare it as |
API keys
A request that authenticates with an API key goes through the same permissions as a password sign-in, with one difference: it carries the key’s roles, which can differ from the roles of the user who issued it. A key’s roles are usually narrower than its owner’s, and each one is an ordinary role that you grant permissions to like any other. readFilter, projectResponse and the rest apply as usual.
Which roles a key may be given is decided here too. A permission that lets a role reach /keys carries an apiKeys block:
{
"_id": "usersIssueKeys",
"roles": ["user"],
"predicate": "path-prefix('/keys')",
"priority": 100,
"apiKeys": {
"roles": ["cli-ro"],
"max-expires-in-days": 90,
"max-keys-per-user": 5
}
}
| Field | Meaning |
|---|---|
|
The roles a key issued under this permission may carry. Required: a non-empty array of distinct role names. |
|
The longest life such a key may have. Optional; the service default applies otherwise, and a user may always ask for less. |
|
How many keys one user may hold at a time. Optional; the service default applies otherwise. |
Three things to know:
-
A permission on
/keyswithout the block issues nothing. Its roles reach the endpoint and get a403that says so. -
A malformed block is refused when the permission is written, with a
400that names the field, whether it comes from the console,ulabaseorcurl. -
The key’s roles need not be roles the user holds. With the example above a
usermay issue acli-rokey, and what that key can do is whatever other permissions grant tocli-ro.
The API Keys page lists the permissions on /keys with the roles each one grants and adds new ones from three fields. They are the same documents you see on the Permissions page.
Priority
Permissions with higher priority numbers are evaluated first. For each of the user’s roles, the first permission that matches decides, together with its mongo options.
| Priority value | Typical use |
|---|---|
|
Specific exceptions that must win over a standard permission: an exact path, a single method. |
|
Standard application permissions. |
|
Catch-all or fallback permissions. |
|
|
|
Tip
|
When two permissions of the same role match a request, the one with the higher number decides. Give the most specific ones the highest numbers. |
A worked example: orders
Three permissions for a typical order system:
/orders{
"_id": "adminsFullOrders",
"roles": ["admin"],
"predicate": "path-prefix('/orders')",
"priority": 10
}
{
"_id": "usersCreateOrders",
"roles": ["user"],
"predicate": "path('/orders') and method('POST')",
"priority": 100,
"mongo": {
"mergeRequest": { "owner": "@user._id" }
}
}
{
"_id": "usersReadOwnOrders",
"roles": ["user"],
"predicate": "path-prefix('/orders') and method('GET')",
"priority": 100,
"mongo": {
"readFilter": { "owner": "@user._id" }
}
}
From a script
| Operation | Endpoint |
|---|---|
List permissions |
|
Create permission |
|
Update permission |
|
Delete permission |
|
On Enterprise plans replace /acl with /restheart/acl in all paths above.
Related pages
-
Users: the users and the roles permissions refer to.
-
Guards: rules checked after permissions, on the user’s state.
-
Root user: where the
rootCanDoEverythingpermission comes from. -
Users and permissions through the API: the requests behind this page.
-
API keys: the
apiKeysblock, and what a request made with a key may do. -
Plans: the collection paths that change on Enterprise.