Interlaken
Authentication

Permissions and scopes

How a permission key is written, how a token's scope narrows it, and what a 403 is telling you.

Authorization is one flat vocabulary of permission keys. A role holds keys, a token's scope holds keys, and a route demands one. There is no second system layered on top.

How a key is written

<resource>:<verb>

vms:create, disks:read, subnets:delete, api_clients:update. The resource is snake_case and plural; the verb is usually read, create, update or delete, with a handful of specific ones such as apps:deploy, agent_sessions:invoke and vms:read_metrics where the action is not CRUD.

There are 262 keys across about fifty resources. GET /api/v1/permissions returns the current list, grouped as the console groups them, and it is the only list that cannot go stale.

Wildcards

A scope entry may be a single key or a resource wildcard:

vms:read        one permission
vms:*           every verb on VMs
*               every tenant-scope permission

* expands to tenant-scope permissions only. Keys in the platform: namespace are excluded from it by construction and are enumerated by exactly one built-in role, so no wildcard anywhere will hand you the operator surface.

Two ways a caller gets its permissions

A user gets them from roles. The role is resolved per tenant, so the same person can be an administrator in one workspace and a reader in another, and the token says which tenant it is for.

An API client carries its permission set literally: the scopes on the token are the permissions, with no role lookup behind them. That is why the grant-time check matters so much. Every scope requested when the client is created, and again when a token is issued, is verified against what the caller holding the pen actually has.

So the chain is: a token can never exceed its client, and a client can never exceed whoever created it.

Reading a 403

{
  "error": "permission denied",
  "required_permission": "vms:create"
}

The body names the key the route wanted. Add it to the client's scopes, or issue a token that does not narrow it away, and the same call succeeds. A 403 never means "this resource does not exist here"; that is a 404.

Picking a scope set

Start from the routes you actually call and take their keys. Every operation page in the reference states the permission it requires at the top, so you can read them off directly.

Then resist widening. vms:* is four permissions when you needed one, and the cost shows up later, when a leaked token could delete what it was only ever supposed to list.

The routes

On this page