Skip to content

Roles & Permissions

Corveil's authorization story is small on purpose: two roles per organization. No third axis, no cross-org carve-outs, no impersonation. This page is the durable reference for anyone asking who can see and do what inside an org — the canonical role list, a per-surface capability matrix, and the invariants the system upholds.

The two roles

Every member of an organization holds exactly one role:

RoleGranted toRemoved by
adminThe org founder on signup; anyone an existing admin promotes; the recipient of a Transfer Admin flow.Demotion or removal by another admin; transfer of ownership. Not by themselves if they are the only admin (see the last-admin invariant).
memberThe default for any invitation; anyone an admin demotes.Removal by an admin; self-removal ("Leave organization").

These are the only two role values. Roles are scoped to one organization — there is no system-wide administrator and no impersonation path. A user's membership is resolved per request against the organization they are acting in.

Capability matrix

The matrix below classifies every org-scoped surface by which role can use it.

Legend: ✅ allowed, ❌ rejected with 403 permission_denied.

Org management

Surfaceadminmember
Read org metadata
Read org usage
Rename / settings

Organizations are provisioned out-of-band (via SSO or seeding), so there is no in-app "create / delete organization" surface.

Members & invitations

Surfaceadminmember
List members
Change member role
Remove member
Leave organization✅ if not the only admin
Transfer admin role
Invite by email
List pending invitations
Revoke invitation
Resend invitation

Other org-scoped resources

Surfaceadminmember
Provider credentials (create / rotate / archive)
Guardrail administration
Models — org toggle
MCP administration (server registry, access, credentials)
Billing — portal link
Billing — checkout
SSO / SCIM / Domain portal✅ (enterprise tier only)
Org data export
Teams (create / update / deactivate / member CRUD)
Worker diagnostics (own org only)

Admin reach over teammates' resources

An admin can also act on a teammate's API keys and per-user usage/logs — the owner of a resource or an admin of that resource's org may use those endpoints. Two things stay owner-only by design:

  • Editing another member's profile. A teammate's display name and personal budget are theirs to set; an admin makes changes through the membership surfaces (role, removal) instead.
  • Creating an API key on a teammate's behalf still requires the admin to name the target user explicitly — there is no implicit "for whoever is signed in" fallback on that path.

Read-only surfaces

A member can read most of the data their org generates — chats, sessions, analytics, audit-log views — subject to per-resource ownership checks (for example, a chat is scoped to the user who created it). Members cannot read other members' API keys. The admin gate applies to writes and to org-management reads (the tables above).

Transfer admin

To hand an organization to someone else, an admin uses Transfer Admin: it promotes the chosen member to admin and demotes the current admin to member in a single step. Because the promote and the demote happen together, the org never passes through a state with zero admins — which is what keeps the last-admin invariant intact even during a handoff.

The org boundary — Diagram E

Two things define the picture: what each role can do, and the fact that a role in one organization grants nothing in another. Virtual API keys sit inside that same boundary — every key is scoped to one org (and a team and a user), and the real provider credentials never leave the gateway.

Reading it:

  • The box is the boundary. Everything an admin manages and everything a member reads lives inside one organization. Nothing crosses the dashed line — a user who is an admin of Org A and a member of Org B is only a member in Org B until an existing Org-B admin promotes them.
  • Admin vs member is a management line, not a data line. Admins hold the write and management surfaces (the left column of the matrix); members read most org data but hold none of the management surfaces.
  • API keys are scoped, and provider keys are shielded. A virtual key is bound to the org, a team, and a user — that scoping is what makes spend and logs attributable. The real provider credentials stay in the vault; a key holder authenticates to the gateway and never sees them.

Invariants

These behaviors are guaranteed and separately tested.

Last-admin invariant

Every organization has at least one admin at all times.

You cannot demote, remove, or "leave organization" your way to an org with zero admins. When an operation would remove the last admin, it is rejected with 409 Conflict and error.type = "last_admin_protected". The dashboard also hides the "Leave organization" and "Change role → member" affordances when you are the only admin, so the 409 is a backstop, not something you normally hit.

To hand an org to someone else and step down, use Transfer Admin, which promotes the new admin and demotes you in one step — never leaving a gap.

Roles are per-org

A user's role in org A says nothing about their role in org B.

Promotion and demotion write a single membership, in a single organization. There is no "admin everywhere" path. An admin of org A who is invited to org B joins as a member and stays a member until an existing org-B admin promotes them.

Roles do not encode plan tier

The set of roles is identical across every plan.

Plan tier gates which features an org can use — not which roles its members can hold. A trial admin and an enterprise admin have identical role-derived capabilities; the differences are usage caps and enterprise-only features (SSO / SCIM / Domain Verification), never the role model itself.

What isn't here

Today there are exactly two roles. Finer-grained roles that come up in conversation — a billing-only admin, or a read-only viewer that can see analytics and audit logs but not create or invite — are not available. Access in Corveil is org-wide by role; per-resource sharing ("this user can edit chat A but not chat B") is ownership, not a role, and is out of scope.