Channel Access Control
Channel entries can be protected at two levels:
- The channel ACL sets the default rule for every entry in the channel.
- The entry ACL can grant or deny access for one specific row.
The entry ACL wins when it explicitly grants an action. A row-level deny also vetoes the channel default, so an entry can stay hidden even when the channel is public.
Channel ACL
The channel acl object accepts one scope for each action:
{
"acl": {
"create": "shared",
"read": "public",
"update": "private",
"delete": "private"
}
}| Scope | Meaning |
|---|---|
public | Anyone can pass this action, including anonymous visitors. |
shared | Any signed-in customer can pass this action. |
private | For read, update, and delete: only the entry owner can pass. For create: any signed-in customer can create. |
none | The channel does not grant the action. A row ACL can still grant access to a specific entry. |
For entries, the owner is stored in _owner. Private read, update, and delete checks compare _owner with the current customer id.
Entry ACL
The entry _acl object is keyed by actor:
{
"_owner": "65f0c6f2c2f48f7a2d1a1111",
"_acl": {
"*": { "read": true },
"users": { "update": false },
"id:65f0c6f2c2f48f7a2d1a1111": { "read": true, "update": true },
"role:members": { "read": true }
}
}Actor keys:
| Actor key | Matches |
|---|---|
* | Everyone for grants. For denies, it blocks anonymous access and public channel defaults. |
users | Any signed-in customer. |
id:<customer_id> | One customer. |
role:<role_name> | Customers assigned to that role. |
Action values are booleans. true grants the action. false denies it. For signed-in customers, use users, id:<customer_id>, or role:<role_name> when you want a deny rule to match them. The API stores negative rules internally as noRead, noUpdate, and noDelete, but clients should send the public shape above.
How Checks Resolve
For read, update, and delete, Nimbu evaluates access in this order:
- If the entry has a positive row-level grant for the action, the current actor must match it.
- If there is no positive row-level grant, the channel ACL decides the default.
- A matching row-level deny vetoes both cases.
That means:
- A channel with
read: publiccan hide one entry with{ "*": { "read": false } }. - A channel with
read: sharedcan hide one entry from all signed-in customers with{ "users": { "read": false } }. - A channel with
read: privatecan still hide an entry from its owner with{ "id:<customer_id>": { "read": false } }. - A channel with
read: nonecan expose one row with a positive row grant such as{ "role:members": { "read": true } }.
REST API Filtering
Channel entry routes apply ACLs for non-master tokens. Master tokens bypass ACLs unless you opt in:
GET /channels/articles/entries?use_acl=true
Authorization: Bearer <master-token>
Session-Token: <customer-session-token>Use Session-Token or X-Nimbu-Session-Token to evaluate the request as a customer. Customer OAuth tokens also resolve the current customer. If no customer can be resolved, ACL checks run as anonymous.
Hidden single entries return 404, not 403. Collection and count routes filter hidden entries out of the result.