modelProviders resource (no separate gatewayProviders resource since the binding model was retired). Permissions are checked scope-aware: every guard names the scope (ORGANIZATION, TEAM, PROJECT) the action operates on, and a higher-scope grant cascades downward (org manage allows team and project actions).
This page documents the default permission matrix. Custom roles can carry any combination of the permissions below, see Custom Roles for how to define one.
Resources
Every gateway UI, tRPC call, and REST endpoint checks one of these seven resource keys:Actions
Each resource supports a subset of the standard CRUD action verbs:
The full permission set uses the
<resource>:<action> format, for example virtualKeys:rotate, gatewayBudgets:manage, gatewayGuardrails:attach, virtualKeys:viewOtherPersonal. Custom roles can pick any subset.
Multi-scope intersection
When a VK is created with multiple scope rows (e.g.TEAM:platform AND TEAM:data-sci), the caller must hold virtualKeys:manage at every named scope. Holding it at only one does not pass; the error names the unauthorised scope. Holding virtualKeys:manage at ORGANIZATION cascades down to every TEAM and PROJECT in the org in a single grant.
Default role matrix
What each default role can actually do
ADMIN: full gateway control. Can mint VKs at any scope, audit other users’ personal VKs (viewOtherPersonal), set budgets (and delete them), edit ModelProvider Advanced (Gateway) settings, attach/detach guardrails, read audit logs, view usage.
MEMBER: can mint + rotate their own VKs, view their own personal VKs, read budgets + providers + guardrails, read audit logs, view usage. Cannot create or delete budgets (finance-level control lives with admins), cannot edit ModelProvider Advanced settings, cannot attach/detach guardrails (policy change belongs to admins), and cannot view other users’ personal VKs.
VIEWER: read-only across every gateway surface. Can see VKs (but cannot see the secret, the secret is only ever shown at create-time, regardless of role), budgets, ModelProvider basic + Advanced fields (read-only), guardrail attachments, audit logs, usage. Cannot see other users’ personal VKs.
CUSTOM: inherits no gateway permissions by default. A custom role starts empty and must be granted the specific permissions you want.
Public REST API scoping
Every/api/gateway/v1/* endpoint enforces the same permission as its equivalent UI action. The mapping is:
Two layers apply on virtual-key writes, exactly as in the dashboard: the route’s permission is the API-key ceiling, and the scopes the call touches are then checked individually (
virtualKeys:manage on every scope at create/re-scope; the op permission on at least one existing scope for update/rotate/revoke). Guardrail attachments travel inside config.guardrailAttachments on create/update and require gatewayGuardrails:attach on the key’s project; there are no separate guardrail routes. Legacy project API keys keep their historical power, full access to their own project and nothing beyond it, so org- and team-scoped provisioning requires a scoped API key with the bindings to prove it.
Audit log retrieval is not exposed via the public REST API in v1, gateway audit rows live in the platform AuditLog table and are read via /settings/audit-log (CSV export) or via the tRPC organization.getAuditLogs procedure (gated on auditLog:view, with TeamUser ADMIN/MEMBER/VIEWER fallback for legacy admins). See Audit log → Querying programmatically. The gatewayLogs:view permission remains in the enum for backward compatibility but is no longer wired to any endpoint.
A request with an API token that lacks the required permission returns 403 permission_denied with the missing permission named in the error.message:
Personal VKs (principal-attributed)
The default role matrix governs who can mint a VK: a VK can also be marked as personal by settingprincipalUserId on the record. The principal column is orthogonal to the VK’s scope rows.
- A VK with
principalUserId = user_abcis treated as that user’s personal credential. Spend cascades through the principal’s PRINCIPAL-scope budget first, then through scope-driven budgets (TEAM, ORGANIZATION). - A VK with
principalUserId = nullis shared (service-account-style): spend cascades through scope-driven budgets only. - The CLI device-flow (
langwatch login --device) lazy-mints a personal VK atORGANIZATIONscope with the caller as the principal. No explicitvirtualKeys:managegrant is required for this self-mint path. - Visibility: a user always sees their own personal VKs without any explicit grant (principal-match short-circuit). Viewing other users’ personal VKs requires
virtualKeys:viewOtherPersonal.
SCIM + SSO
Default role matrix assignments flow through SCIM, when an IdP pushes a user with roleMEMBER, they pick up the gateway permissions in the MEMBER column above. Custom roles must be assigned via LangWatch UI (SCIM doesn’t carry custom-role identifiers); the SCIM integration only maps to ADMIN, MEMBER, VIEWER.
Changing the permission matrix
Default roles are code-defined inlangwatch/src/server/api/rbac.ts, see commit history for the shipping order. Do not edit the default matrix in production: changes to TEAM_ROLE_PERMISSIONS affect every team on the instance. Use a custom role instead: create it in the UI, assign the permissions you want, and assign it to specific users.
For the policy rationale (why MEMBER can mint VKs but not create budgets, etc.), see spec contract §10, Permissions.
See also
- Virtual Keys: lifecycle, rotation, revoke semantics.
- Budgets: scope semantics + breach behaviours.
- API Reference: Management: all REST endpoints with their permission requirements.
- Security: threat model, secret handling, HMAC/JWT cryptography.