Skip to content

Permissions

This page shows how OpenBot decides if a caller may do something. Every call to /v1 needs one or more permissions. OpenBot checks them before the call runs.

The model has four parts:

Part What it is
Permission group A named set of actions on one kind of resource, such as sessions.read.
Resource key The name of one resource, such as one Session.
Policy Says allow or deny for some permission groups on some resources.
Role A named set of policies, such as Member or Administrator. Organizations can add their own.

A member gets the policies of their roles, plus their own extra policies. A user token gets the policies of its member, and also its own policies. The platform can add deny policies for every organization. See The order of checks.


Permission groups

List them with GET /v1/organization/permission_groups.

ID Resource What it allows
responses.run Session Start, steer, queue and resume work in a Session.
sessions.read Session Read Sessions, their history, memory and delegations.
sessions.write Session Create, change, fork, restore, interrupt and delete Sessions.
requests.resolve Request Answer the requests of your Agents for new capabilities.
agents.read Agent Read Agents, their memory, Rules and Grants.
agents.write Agent Create and change Agents, their memory, Rules and Grants.
agents.delegate Agent Give work to an Agent, from a client or from another Agent.
connections.read Connection Read App connections and App accounts.
connections.write Connection Create, change and delete App connections, and sign in to App accounts.
apps.use Apps Find Apps, and use App operations and App views.
apps.publish Apps Use the developer tools for Apps that you publish.
models.use Model Choose a model for a Session.
tokens.read User List API tokens.
tokens.write User Create and revoke API tokens.
organization.read Organization Read the organization settings.
organization.write Organization Change the organization settings.
members.read Organization List members, their roles and their policies.
members.write Organization Change the roles, policies and status of members, and remove members.
roles.write Organization Create, change and delete the custom roles of the organization.
model_providers.read Organization Read the model providers of the organization. Keys are never shown.
model_providers.write Organization Add, change and remove the model providers and keys of the organization.
sso.read Organization Read the email domains and SSO connections.
sso.write Organization Add and verify email domains, and change SSO connections.
audit_logs.read Organization Read the audit log.
platform.read Platform Read the platform settings, organizations, admins and shared model providers.
platform.write Platform Change the platform settings, organizations, admins and shared model providers.

organization.read and organization.write also cover the organization settings. platform.read and platform.write only work on the resource openbot.platform, and only for platform admins. See Platform groups.

The API reference lists the routes. The contract in @openbot-build/api says which permission each route needs.


Resource keys

A resource key is a name with parts that dots separate:

Resource Key
The organization openbot.org.<org>
One member openbot.org.<org>.user.<user>
One Session openbot.org.<org>.user.<user>.session.<session>
One Agent of a member openbot.org.<org>.user.<user>.agent.<agent>
One shared Agent openbot.org.<org>.agent.<agent>
The requests of a member openbot.org.<org>.user.<user>.request
One connection openbot.org.<org>.user.<user>.connection.<connection>
The Apps of a member openbot.org.<org>.user.<user>.apps
One model provider openbot.org.<org>.model.<provider>
The whole platform openbot.platform

A key covers itself and every key below it. So openbot.org.<org> covers everything in the organization, and openbot.org.<org>.user.<user> covers everything of one member.

In a policy, you can write two placeholders:

  • {org} is the ID of the organization.
  • {self} is the user ID of the caller. For a token, it is the member of the token.

A dot inside an ID is written as %2E, so it never looks like a new part.


Policies

A policy looks like this:

{
"effect": "allow",
"permissionGroups": ["sessions.read", "sessions.write"],
"resources": ["openbot.org.{org}.user.{self}"]
}

OpenBot decides in this order:

  1. If a matching policy says deny, the answer is no.
  2. If a matching policy says allow, the answer is yes.
  3. If no policy matches, the answer is no.

A policy matches when it names the permission group, and one of its resources covers the key of the request.

A policy can only name resources in its own organization. Otherwise OpenBot returns 400. Only the policies of a token can also name openbot.platform.

Limit models

models.use on openbot.org.<org>.model.<provider> covers the models of one model provider. Use it to limit which providers a member may choose. This policy stops a member from using one provider:

{
"effect": "deny",
"permissionGroups": ["models.use"],
"resources": ["openbot.org.{org}.model.prov_4c1e..."]
}

The order of checks

OpenBot checks three sets of policies, in this order:

  1. The policy ceiling of the platform. It only has deny policies, and they apply in every organization. See Platform.
  2. The member policies: the policies of the member’s roles, plus their extra policies.
  3. The token policies, when the caller uses a user token.

A deny anywhere means no. Each set after the ceiling must also allow the call.

Tokens never do more than their member

A user token has two sets of policies: the policies of its member and its own policies. Both sets must say yes. 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 policies gets this policy. It allows everything in the organization except managing tokens. It never includes platform.read or platform.write:

{
"effect": "allow",
"permissionGroups": [
"responses.run",
"sessions.read",
"...",
"audit_logs.read"
],
"resources": ["openbot.org.{org}"]
}

This example makes a token that can only read your Sessions:

Terminal window
curl -b cookies.txt \
-H "Origin: https://api.example.com" \
-H "Content-Type: application/json" \
-d '{"name":"Dashboard","policies":[{"effect":"allow","permissionGroups":["sessions.read"],"resources":["openbot.org.{org}.user.{self}"]}]}' \
https://api.example.com/v1/user/tokens

Roles

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.

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 and its shared Agents, and read the audit log. Work only with your own Sessions and connections.
administrator_read_only Read the organization, its members and the audit log, and use the shared Agents. Work only with your own Sessions and connections.
member Work with your own Agents, Sessions, connections and tokens, use the shared Agents and the models of the organization, and read its settings.
auditor Read the organization, its members and the audit log. Nothing else.

Some built-in roles also hold the groups for roles, model providers and SSO:

Role Extra groups for organization features
super_administrator Every permission group, except platform.read and platform.write.
administrator roles.write, model_providers.read, model_providers.write, sso.read, sso.write.
administrator_read_only model_providers.read, sso.read.

To give a member less than a role, add a deny policy to the member. This example stops a member from running work, but lets them read their Sessions:

Terminal window
curl -X PATCH -b cookies.txt \
-H "Origin: https://api.example.com" \
-H "Content-Type: application/json" \
-d '{"policies":[{"effect":"deny","permissionGroups":["responses.run"],"resources":["openbot.org.{org}"]}]}' \
https://api.example.com/v1/organization/members/u_456

Custom roles

An organization can add its own roles. A custom role has a name, a description and policies. Its ID starts with role_. Creating, changing and deleting custom roles needs roles.write.

Terminal window
curl -H "Authorization: Bearer $OPENBOT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Reviewer","description":"Reads Sessions and answers requests.","policies":[{"effect":"allow","permissionGroups":["sessions.read","requests.resolve"],"resources":["openbot.org.{org}.user.{self}"]}]}' \
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 policies of a role cannot give anything that you cannot do yourself. Otherwise OpenBot returns 403 with PermissionDenied.
  • A change applies to every member with the role at once.
  • You cannot delete a role while a member or the defaultRoles of the organization use it. OpenBot returns 409 with RoleInUse.

Give a custom role to a member with PATCH /v1/organization/members/:userId. See Organization.


Platform groups

platform.read and platform.write are for platform admins. They only work on the resource openbot.platform.

  • No role in an organization gives them, not even super_administrator.
  • A policy ceiling or a member policy cannot give them.
  • A user token of a platform admin gets them only when its own policies name them on openbot.platform.

See Platform for an example token.


Errors

Status Error When
403 PermissionDenied No policy allows the call, or a policy 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 AuthorizationUnavailable OpenBot cannot read the roles and policies of the caller right now.

The body of PermissionDenied names the permission and the resource key:

{
"_tag": "PermissionDenied",
"permission": "sessions.write",
"resource": "openbot.org.org_8f3a.user.u_123.session"
}

You can only reach your own Sessions and connections. A Session of another member answers 404, as if it does not exist.