Roles and permissions

Two layers, and they are not the same

The other layer is connection scopes, enforced by your Worker rather than by us — the credential model explains why that separation exists. Organizations and teams is where a role is assigned, and the audit trail is where its use shows up.

Roles in the dashboard decide what a member of your organization may do in the UI.

Scopes on the connection decide what the credential may do against your Worker.

Scopes name operations, not people

A credential that may read purchases cannot revoke an entitlement unless separately scoped, and anything unscoped is denied.

Matching is exact. No prefix rule, no wildcard — payments:entitlements does not confer payments:entitlements:revoke.

Two checks, against two different things

The connection row records what you granted.

The token carries the single scope the current call needs — not the whole grant.

Both must agree, which is why one call is never as dangerous as the most dangerous one you allowed.

Grant and revoke are two scopes for a reason

They have different blast radii.

Grant mints paid product out of nothing. Revoke takes paid access from a live customer.

A refund tool needs revoke and never grant. One admin flag would make each of them the other.

The three that are worth withholding deliberately

audit:events:read_detail — IP, user-agent and metadata one event at a time is a forensic read; the same fields across a hundred rows is bulk harvesting.

secrets:status:read — the list of which credentials a project holds, which are stale, and which no automation will ever rotate is a map of where to push. You must be able to grant a users pane without also granting that.

secrets:rotate — separate again, because matching is exact and a rotation behind the status scope would have handed credential replacement to everybody who ever wanted a status pane, retroactively and without being asked.

What no scope can grant

Reading a secret’s value. There is no route that does and no scope that could.

The reason a secret is encrypted under a key only your Worker holds is that no third party has a path to the plaintext — and a route here would be that path in every deployment, whether or not anybody granted it.

Impersonating a user. The most dangerous administrative capability there is, and it gets its own design and security review rather than riding in on a batch.

Writing to a balance ledger. Read-only, permanently.

Erasing an audit row. A credential that could would be able to erase the evidence of its own use.

Every administrative action is audited

In your trail, under the control-plane actor kind, carrying the connection id and the dashboard user’s own subject — so a shared team credential still distinguishes who acted.

ESC