The tenancy hierarchy
Hierarchy
workspaces.org_id is a plain column, and org-level commercial state lives on billing_accounts, anchored to a designated billing workspace.
A workspace carries an environment: dev, stage, or prod. The environment is part of both visibility and authorization, and the rule is absolute — a dev key can never reach a prod connection.
workspace_id is the isolation boundary
Every Postgres row and every Redis key carries workspace_id. That is tenant isolation; there is no second mechanism (ADR-0006).
Scoping
- Snapshots are per-workspace. Control compiles one bundle of keys, connections, tools, and the Cedar policy set for each workspace. The gateway and control never read another workspace’s activation, even for a shared publisher artifact: under ADR-0020 enabling one materializes an immutable, content-addressed bundle row and snapshot entry for that workspace. That materialization is unbuilt — there is no
connector_bundlestable, and control reads a reviewed pack off disk instead. - Control’s API is not an oracle for workspace ids. On
/api/v1/workspaces/{workspace_id}/…, membership resolves before the action, so a non-member receives the same404that a non-existent workspace returns. A403is only ever seen by a member whose role lacks the action.
Three authentications
- Dashboard (human)
- Inbound (agent)
- Outbound (vendor)
A Clerk session identifies an operator in the browser (ADR-0033). Account creation is invitation-gated by the Clerk instance.After authentication, control still owns workspaces, membership, and every
workspace_id: each /api/v1 route verifies the session against the issuer’s published JWKS, resolves membership, and applies one named action — never a role, org, or claim taken from the browser.A dashboard session never becomes a virtual key or an MCP JWT, never reaches the gateway, and never carries an authorization decision. Clerk holds no vendor secret and no key-encryption material.With no issuer configured, control’s operator routes answer 503 and the dashboard refuses to serve. Fail-closed is the specified behavior.Inbound versus outbound, concretely
Credential flow
ADR-0024 requires that a worker never see a vendor credential and never call a vendor: it returns a bounded, bundle-declared request plan, and the gateway validates it, injects the credential, and performs the HTTP itself. That protocol is not implemented — the shipped
WorkerExecutor still runs ADR-0014’s hand-off and would send the credential to a worker in x-obol-upstream-authorization. No worker exists to receive it, so no credential crosses that hop today. The tier is parked (ADR-0058). See Trusted workers.
Custody modes
A connection records how the vendor credential is held.
Even under federated custody, invariant 8 holds on the vendor-facing identity: every broker account and broker OAuth client is workspace-scoped. Pooled platform-wide broker keys and a shared broker OAuth app are forbidden.
Hybrid custody — Obol vaulting a read-only credential alongside a broker-held write credential, which is the only path by which a federated write reaches
verified — is explicitly deferred to phase 2 and requires amending the connection contract. It does not ship today.What a virtual key carries
A key is not merely an authenticator; it is the scope object.
Keys can also run in progressive mode, exposing only
search_tools and call_tool instead of the full catalog, which keeps large tool schemas out of the model’s context window.
See Virtual keys for minting, rotation, and revocation.
Human roles are control-owned, not Cedar
Cedar authorizes agent traffic. Operator permissions in the dashboard are a separate, control-owned mechanism over a closed role vocabulary (ADR-0037).
An unknown stored role fails closed. Every workspace-scoped operation applies exactly one of eleven named actions —
workspace.read, key.manage, policy.draft, policy.publish, connection.manage, routing.publish, approval.decide, approval.policy.manage, audit.read, usage.read, membership.manage — and the test inventory is derived from the generated OpenAPI paths rather than hand-listed, so a new route fails the suite until someone assigns it an action.
A matching approval policy can further restrict whether an admin or owner may decide a particular held call. Approval permission never substitutes for Cedar tool permission.
Virtual keys
Minting, scoping, and revocation.
Vault
Envelope encryption and KEK providers.
Credential brokering
Native custody, federated custody, and what each one can prove.
Invariants
Rules 1, 5, and 8 in full.