Permissions
For organization administrators. You need the rights named for each task. Only a
platform admin can change settings under /v1/platform. Start with the
administrator manual.
This page shows how OpenBot decides if a caller may do something. Every call to
/v1 names what it needs: an action on a resource. OpenBot checks it before the
call runs.
OpenBot uses the ability library for this work. The model has four parts:
| Part | What it is |
|---|---|
| Resource | A kind of thing to act on, such as a Chat or a Bot. Each one has a list of actions and a path. |
| Rule | Says Allow or Deny for some actions on some resources, when its condition is true. |
| Policy | A tree of rules. It gives one answer for a request: allow, deny, or no answer. |
| Role | A named policy, such as Member or Administrator. Organizations can add their own. |
A member gets the policies of their roles, plus their own member policy. A user token also has its own policy, and both must allow the call. The platform can add a ceiling with deny rules for every organization. See The order of checks.
Resources and actions
Section titled “Resources and actions”List them with GET /v1/organization/resources. Each item has the kind, the
actions, the fields and the path of one resource.
| Resource | Action | What it allows |
|---|---|---|
Chat |
read |
Read Chats, their history and the work that they gave away. |
Chat |
write |
Change, interrupt and delete Chats, and cancel the work that they gave away. |
Chat |
run |
Send messages to Bots, so that they work in a Chat. |
File |
read |
Read your files and their bytes. |
File |
write |
Upload and delete your files. |
Request |
resolve |
Answer the requests of your Bots for new capabilities. |
Bot |
read |
Read Bots, their memory, Rules and Grants. |
Bot |
write |
Create and change Bots, their memory, Rules and Grants. |
Bot |
delegate |
Give work to a Bot, from a client or from another Bot. |
Bot |
share |
Invite people to use a Bot, and manage its members. |
Trigger |
read |
Read triggers: their schedules and webhooks. |
Trigger |
write |
Create, change and delete triggers, and set their webhook secrets. |
Channel |
read |
Read the Channels of the organization and the people linked to them. |
Channel |
write |
Create, change and delete Channels, set their secrets, and unlink people. |
Channel |
use |
Talk with the Bot of a Channel, and let your Bots post to it. |
ChannelIdentity |
read |
Read your linked accounts on the platforms of Channels. |
ChannelIdentity |
write |
Link and unlink your accounts on the platforms of Channels. |
Computer |
read |
Read Computers, the Bots that may use them, and their usage. |
Computer |
write |
Create, change and delete Computers, pair machines, and make connector tokens. |
Computer |
use |
Run commands, change files, open ports and use the desktop, and let your Bots use them. |
ComputerProvider |
read |
Read the accounts at Computer providers. |
ComputerProvider |
write |
Add, change and delete accounts at Computer providers, and their keys. |
ComputerProvider |
use |
Create Computers with an account at a Computer provider. |
Vault |
read |
Read Vaults, their items, and the Bots that may use them. Secrets are never shown. |
Vault |
write |
Add, change and delete Vaults and their items, and set their values. |
Vault |
use |
Let your Bots use Vaults in Code Mode. |
SecretProvider |
read |
Read the accounts at secret providers. |
SecretProvider |
write |
Add, change and delete accounts at secret providers, and their tokens. |
SecretProvider |
use |
Let Vault items read their secrets from an account at a secret provider. |
Connection |
read |
Read App connections and App accounts. |
Connection |
write |
Create, change and delete App connections, and sign in to App accounts. |
App |
use |
Find Apps, and use App operations and App views. |
App |
publish |
Use the developer tools for Apps that you publish. |
Model |
use |
Choose a model for a Chat, and see it in the model catalog. |
Token |
read |
List API tokens. |
Token |
write |
Create and revoke API tokens. |
Organization |
read |
Read the organization and its settings. |
Organization |
write |
Change the organization and its settings. |
Member |
read |
List members, their roles and their policies. |
Member |
write |
Change the roles, policies and status of members, and remove members. |
Role |
write |
Create, change and delete the custom roles of the organization. |
ModelProvider |
read |
Read the models and model providers of the organization. Keys are never shown. |
ModelProvider |
write |
Add, change and remove the models, model providers and keys of the organization. |
Sso |
read |
Read the email domains and SSO connections. |
Sso |
write |
Add and verify email domains, and change SSO connections. |
AuditLog |
read |
Read the audit log. |
Usage |
read |
Read the model usage and its cost, and the credits of the organization. |
Budget |
read |
Read the budgets and how much of them is spent. |
Budget |
write |
Create, change and delete budgets. |
Platform |
read |
Read the platform settings, organizations, admins and shared models and model providers. |
Platform |
write |
Change the platform settings, organizations, admins and shared models and model providers. |
Platform is only for platform admins. See The platform.
The API reference lists the routes. The contract in @openbot-build/api
says which action each route needs.
A path puts each resource in a tree. A rule can cover a part of the tree.
| Resource | Path |
|---|---|
Chat, File, Request, Connection |
org / <org> / user / <user> / <kind> / <id> |
Bot, Trigger, Computer, ComputerProvider, Vault, SecretProvider |
org / <org> / user / <owner> / <kind> / <id> |
App, Token, ChannelIdentity |
org / <org> / user / <user> / <kind> |
Channel |
org / <org> / channel / <id> |
Model |
org / <org> / model / <provider> / <id> |
Organization, Member, Role, ModelProvider, Sso, AuditLog, Usage, Budget |
org / <org> |
Platform |
platform |
The kind part is the kind in small letters, with _ between words, such as
computer_provider. App uses apps.
A shared Bot, trigger, Computer, Computer provider, Vault or secret provider has
no owner. Its ownerUserId field is null. A Bot that another Bot owns has the
owner at the top of its owner tree. When a Bot makes a Bot, the member it works
for needs write on Bots of that owner.
Policies
Section titled “Policies”A policy is JSON text. The HTTP fields policy and ceiling are strings in
requests and responses. To send a policy object, use JSON.stringify(policy)
once for that field, then encode the outer request as JSON. The typed client
does this with the policy Codec (the Schema that reads and writes the policy).
The text below lets the caller read and change their own Chats:
{ "_tag": "Rules", "algorithm": "denyOverrides", "rules": [ { "_tag": "Allow", "actions": ["read", "write"], "resources": ["Chat"], "when": { "_tag": "Under", "prefix": [ { "_tag": "Literal", "value": "org" }, { "_tag": "Principal", "path": "organizationId" }, { "_tag": "Literal", "value": "user" }, { "_tag": "Principal", "path": "userId" } ] } } ]}OpenBot checks every policy when it reads it. A kind, an action or a field that
does not exist gives 400. A policy in a request may have at most 100 rules,
and may be at most 8 levels deep.
Ability 3.1.0 has no library size, depth or search limits. The OpenBot request
limits above still apply. Field lists use real paths or *; patterns such as
owner* are not valid.
When you move from Ability 2 to 3, stop all servers and run openbot-migrate.
The migration changes the platform ceiling from an object to JSON text. Role,
member and token columns already hold JSON text. Clients must send strings for
policy and ceiling. Old policies must use valid fields. A policy that cannot
load grants no access.
A rule has these fields:
| Field | What it is |
|---|---|
_tag |
Allow or Deny. |
actions |
The actions. * is every action. |
resources |
The kinds, such as Chat. * is every kind. |
when |
Optional. The condition. Without it, the rule covers every value of the kinds. |
reason |
Optional. A reason. A Forbidden error from a deny rule shows it. |
A list of rules has an algorithm. It decides which rule gives the answer when
more than one rule applies:
| Algorithm | Winner |
|---|---|
denyOverrides |
A deny rule wins over every allow rule. |
permitOverrides |
An allow rule wins over every deny rule. |
firstApplicable |
The first rule that applies. |
lastApplicable |
The last rule that applies. |
A policy can also put policies together:
| Node | Answer |
|---|---|
{"_tag":"All","policies"} |
Every policy must allow. One deny is enough to deny. |
{"_tag":"Any","policies"} |
One allow is enough. |
{"_tag":"FirstOf","policies"} |
The first policy that allows or denies. |
{"_tag":"Ceiling","cap","policy"} |
A deny from cap always wins. An allow from cap does nothing. |
Conditions
Section titled “Conditions”A condition tests the fields and the path of a resource:
| Node | True when |
|---|---|
{"_tag":"Compare","op","field","value"} |
The field compares to the value. op is eq, ne, lt, lte, gt or gte. |
{"_tag":"In","field","values"} |
The field is equal to one of the values. |
{"_tag":"Exists","field"} |
The field is not null. |
{"_tag":"Under","prefix"} |
The path of the resource starts with the prefix. |
{"_tag":"And"/"Or","conditions"} |
Logic. |
{"_tag":"Not","condition"} |
Logic. |
{"_tag":"True"}, {"_tag":"False"} |
Always, or never. |
A value is {"_tag":"Literal","value":...}, or a field of the caller:
{"_tag":"Principal","path":"userId"} or "organizationId". A field of the
caller with no value never matches, also with ne.
These conditions are the ones you need most:
| Condition | Covers |
|---|---|
Under with org, the organizationId of the caller |
Everything in the organization. |
Under with org, organizationId, user, userId |
Everything of the caller. |
Compare eq on ownerUserId with null |
The shared Bots, triggers or Computers. |
Compare eq on id |
One resource. |
Every policy of a member only works in the organization of the member. A rule that names another organization gives nothing.
Limit models
Section titled “Limit models”use on Model covers the models that a member may choose for a Chat.
GET /v1/organization/model_catalog only shows these models. This rule stops a
member from using one model provider:
{ "_tag": "Deny", "actions": ["use"], "resources": ["Model"], "when": { "_tag": "Compare", "op": "eq", "field": "provider", "value": { "_tag": "Literal", "value": "prov_4c1e..." } }}The order of checks
Section titled “The order of checks”OpenBot checks three policies:
- The ceiling of the platform. It only has deny rules, and they apply in every organization. See Platform.
- The member policy: the policies of the member’s roles, plus their own member policy. A deny rule in any of them wins.
- The token policy, when the caller uses a user token.
A deny anywhere means no. The member policy, and the token policy when there is one, must also allow the call. With no answer, the answer is no.
OpenBot reads these policies again for each check. So a change to a role, a member or a token works at once.
An execution keeps its resource owner separate from the person who started it. For Channel work, the speaker and each saved caller must pass the policy on the actual resource owner. A later check reads their current rights again. An approval cannot change that owner or remove a token limit.
A list, such as GET /v1/triggers, only has the resources that the caller may
read. OpenBot changes the policy into a condition on the list, for most lists in
the database query itself. So a deny rule on one resource hides it from the list
too.
List conditions and direct checks give the same answer for a missing owner. For
example, NOT (ownerUserId = "member") includes a shared resource whose
ownerUserId is null.
Lists of Chats, files, App connections and Channels apply the policy in the database query. A deny rule hides only the matching items. With no items that the caller may read, the list is empty. File pages and their next cursor count only the files that the caller may read. A file cursor must still belong to the caller and pass the current read policy.
Creating a Chat, file, App connection or Channel still needs write on the full
scope of that kind. List filtering does not give write access.
Tokens never do more than their member
Section titled “Tokens never do more than their member”A user token must pass its own policy and the policy of its member. So a token can do less than its member, but never more. If an administrator takes a role away from the member, every token of that member loses it too.
A token made without policy gets this policy. It allows every act of its
member, except acts on tokens and on the platform:
{ "_tag": "Rules", "algorithm": "denyOverrides", "rules": [ { "_tag": "Allow", "actions": ["*"], "resources": ["Chat", "File", "Request", "...", "Budget"] } ]}This example makes a token that can only read your Chats:
curl -b cookies.txt \ -H "Origin: https://api.example.com" \ -H "Content-Type: application/json" \ -d '{"name":"Dashboard","policy":"{\"_tag\":\"Rules\",\"algorithm\":\"denyOverrides\",\"rules\":[{\"_tag\":\"Allow\",\"actions\":[\"read\"],\"resources\":[\"Chat\"]}]}"}' \ https://api.example.com/v1/user/tokensThe rule has no condition, but the policy of the member still limits the token to what you may read.
List them with GET /v1/organization/roles. The list has the built-in roles and
the custom roles of the organization. Each role has builtin: true or
builtin: false, and its policy.
Built-in roles
Section titled “Built-in roles”Every organization has these roles. They cannot change. A change returns 409
with RoleReadOnly.
| Role | What it can do |
|---|---|
super_administrator |
Everything in the organization. Only a Super Administrator can give or take away this role. |
administrator |
Manage the organization, its members, its shared Bots, its shared triggers, its shared Computers and its Channels, and read the audit log. Work only with your own Chats and connections. |
administrator_read_only |
Read the organization, its members, usage, budgets and the audit log, and read the shared Bots, triggers, Computers and Channels. Work only with your own Chats and connections. |
member |
Work with your own Bots, Chats, triggers, Computers, connections and tokens, use the shared Bots, triggers, Computers, Channels and models of the organization, and read its settings. |
auditor |
Read the organization, its members, usage, budgets and the audit log. Nothing else. |
Some built-in roles also act on roles, model providers, SSO, Channels, usage and budgets:
| Role | Extra resources for organization features |
|---|---|
super_administrator |
Every action on every resource, except Platform. |
administrator |
Every action on Role, ModelProvider, Sso, Channel, Usage and Budget. |
administrator_read_only |
read on ModelProvider, Sso, Channel, Usage and Budget. |
auditor |
read on Usage and Budget. |
To give a member less than a role, give the member a policy with deny rules. This example stops a member from running work, but lets them read their Chats:
curl -X PATCH -b cookies.txt \ -H "Origin: https://api.example.com" \ -H "Content-Type: application/json" \ -d '{"policy":"{\"_tag\":\"Rules\",\"algorithm\":\"denyOverrides\",\"rules\":[{\"_tag\":\"Deny\",\"actions\":[\"run\"],\"resources\":[\"Chat\"]}]}"}' \ https://api.example.com/v1/organization/members/u_456Custom roles
Section titled “Custom roles”An organization can add its own roles. A custom role has a name, a description
and a policy. Its ID starts with role_. Creating, changing and deleting custom
roles needs write on Role.
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"Reviewer","description":"Reads Chats and answers requests.","policy":"{\"_tag\":\"Rules\",\"algorithm\":\"denyOverrides\",\"rules\":[{\"_tag\":\"Allow\",\"actions\":[\"read\",\"resolve\"],\"resources\":[\"Chat\",\"Request\"],\"when\":{\"_tag\":\"Under\",\"prefix\":[{\"_tag\":\"Literal\",\"value\":\"org\"},{\"_tag\":\"Principal\",\"path\":\"organizationId\"},{\"_tag\":\"Literal\",\"value\":\"user\"},{\"_tag\":\"Principal\",\"path\":\"userId\"}]}}]}"}' \ https://api.example.com/v1/organization/roles| Route | What it does |
|---|---|
POST /v1/organization/roles |
Creates a custom role. |
GET /v1/organization/roles/:roleId |
Reads one role. |
PATCH /v1/organization/roles/:roleId |
Changes a custom role. |
DELETE /v1/organization/roles/:roleId |
Deletes a custom role. |
- The allow rules of a role cannot give anything that you cannot do yourself.
OpenBot tests each allow rule with you as the caller. You must be able to do
its actions on every value that the rule allows in the organization. The
answer is exact: it looks at the fields and the path of the resource. A rule
that allows no value gives nothing, so it passes. Otherwise OpenBot returns
403withForbidden. - A change applies to every member with the role at once.
- You cannot delete a role while a member or the
defaultRolesof the organization use it. OpenBot returns409withRoleInUse.
Give a custom role to a member with PATCH /v1/organization/members/:userId.
See Organization.
The platform
Section titled “The platform”The actions on Platform are for platform admins. Its path is platform, so no
rule about an organization covers it.
- No role in an organization gives them, not even
super_administrator. - The ceiling does not apply to them, so a ceiling never locks out the platform admins.
- A user token of a platform admin gets them only when its own policy allows them.
See Platform for an example token.
Errors
Section titled “Errors”| Status | Error | When |
|---|---|---|
400 |
Schema error | A policy names a kind, an action or a field that does not exist. |
403 |
Forbidden |
No rule allows the call, or a rule denies it. See the body below. |
404 |
RoleNotFound |
The organization has no role with this ID. |
409 |
RoleReadOnly |
You tried to change or delete a built-in role. |
409 |
RoleInUse |
A member or the default roles still use the role. |
503 |
PolicyUnavailable |
OpenBot cannot read the roles and policies of the caller right now. |
The body of Forbidden names the action and the kind. It has the reason of a
deny rule when one gave the answer:
{ "_tag": "Forbidden", "action": "write", "kind": "Chat"}You can only reach your own Chats and connections. A Chat of another member
answers 404, as if it does not exist. A Bot, trigger or Computer that you may
not read answers 404 in the same way.