Skip to main content
LangWatch RBAC has two layers, two surfaces, and one stitching mechanism:
  • Two layers: organization roles (org-wide capabilities, e.g. ADMIN, MEMBER, EXTERNAL) and team roles (per-team capabilities, e.g. ADMIN, MEMBER, VIEWER).
  • Two surfaces: /settings/roles (the role catalog: pre-built + custom) and /settings/role-bindings (who is bound to what role at what scope).
  • One stitching mechanism: a RoleBinding row glues a user to a role at a scope (organization, team, project, or governance subscope).
The pre-built roles cover the common cases. You only land here when you need to delegate aiTools:manage without granting full organization:manage, or when an audit asks “who can read the audit log” and you want a screen instead of a Slack thread.
Pairs with: Members & invites (assigning roles when inviting), Audit log (every role binding mutation records a row), and AI Gateway → RBAC (the gateway-side enforcement of permissions).

Organization roles

The three pre-built org roles. Each user in the org has exactly one. The minimum-privilege default is intentional: an ORGANIZATION role binding for a MEMBER does not grant team-level access. Team-level permissions come from team-role bindings (next).

Seats

Paid plans meter seats, and there are two kinds. Which one a person occupies follows from what they can do, not from a separate billing switch:
  • A full seat is someone who can change things.
  • A lite seat is someone who can only look at what the team produces.
ADMIN and MEMBER are always full seats. EXTERNAL is a lite seat on its built-in permissions. Assign a custom role to an EXTERNAL member and that role decides the seat instead: if it grants anything beyond viewing, they can change things and count as a full seat from then on. The rule reads the custom role, not the built-in defaults, which is why annotations below stay part of a lite seat while a custom role granting only annotations:create would make the same person a full one. If you want a reviewer who annotates, leave them on the built-in lite role rather than building a custom role for it.

What a lite member can do

They can open the projects they are invited to and read what the team produces there: Annotations are the exception: on the built-in lite role a member can leave and edit them, so reviewers can mark up what they read without needing a full seat. These are permissions, not screens, so they hold wherever the data is reached. A lite member using the MCP server with their own account, or the API with their own credentials, sees exactly what they see in the app.
Trace viewing is included in a lite seat. If you want someone who cannot open a trace at all, build a custom role that withholds traces:view and bind it to them.

Choosing between them

The question to ask about a person is whether they need to change anything. Someone who reviews output, watches dashboards and comments on what they find is a lite seat. Someone who builds prompts, runs experiments, edits datasets, or configures the gateway is a full seat.

Team roles

The four pre-built team roles. A user can have different team roles on different teams (ADMIN on Engineering, VIEWER on Marketing). A user’s effective permissions on a resource are the union of every binding that applies, org-level baseline + team-level baseline + any custom-role overrides.

Permission catalog

Every gate in the codebase is a string of the shape <resource>:<verb>. The full catalog (abridged):
  • Organization: organization:view, organization:manage, organization:delete.
  • Governance: governance:view, governance:manage, ingestionSources:*, anomalyRules:*, complianceExport:view, activityMonitor:view.
  • AI Tools Portal: aiTools:view (everyone), aiTools:manage (admin).
  • Audit log: auditLog:view (team-level by default; note the audit log UI page is gated to organization:manage, the underlying procedure is on auditLog:view).
  • Per-team resources: project:*, analytics:*, traces:*, virtualKeys:*, gatewayBudgets:*, gatewayProviders:*, routingPolicies:*, gatewayGuardrails:*, gatewayLogs:*, gatewayUsage:*, gatewayCacheRules:*, evaluations:*, datasets:*, workflows:*, prompts:*, scenarios:*, secrets:*.

What organization:manage gates today

The legacy /settings/{audit-log, teams, members, roles, groups} pages all require organization:manage (admins only). Underlying tRPC procedures match, role.getAll, organization.getAllOrganizationMembers, organization.getOrganizationPendingInvites, team.getTeamsWithRoleBindings, organization.getMemberById, group.getById, group.listForMember, group.listAll, limits.checkAndSendUsageLimitNotification are all gated to organization:manage server-side. Picker procedures (team.getTeamsWithMembers, team.getTeamWithMembers, organization.getOrganizationWithMembersAndTheirTeams) intentionally stay on organization:view so non-admin pickers (the AddAutomationDrawer, GroupBindingInputRow, project pickers, onboarding flows) continue working, but they redact other members’ email addresses to null for non-admin callers and strip other users’ Personal Workspaces from the result entirely.

The role catalog at /settings/roles

The catalog page lists every role available in the org:
  • 4 pre-built org roles (ADMIN, MEMBER, EXTERNAL, VIEWER).
  • 4 pre-built team roles (ADMIN, MEMBER, VIEWER, CUSTOM).
  • Any custom roles your admin has authored (see below).
Pre-built rows are read-only: you can’t change what MEMBER does, because the gateway and the control plane both encode those defaults. Custom rows are editable.

Custom roles

Custom roles are how you say “let bob@acme.test manage the AI Tools Portal but not the rest of the org.” They’re a RoleBinding row whose role = "CUSTOM" and whose customRoleId references a CustomRole row whose permissions JSON column lists exactly the gates that role grants. To create one:
  1. Open /settings/roles+ New custom role.
  2. Name the role (e.g. aitools-curator).
  3. Tick the permissions to grant. Permissions are scope-aware, granting aiTools:manage at organization scope is different from granting it at team scope.
  4. Save.
To bind the role to a user:
  1. Open /settings/role-bindings+ New binding.
  2. Pick the user, pick the role (aitools-curator from the catalog), pick the scope (Organization, a specific team, a specific project, a governance subscope).
  3. Save.
The binding is now active. The user’s effective permissions are the union of:
  • Their org-role defaults (e.g. MEMBER → organization:view + aiTools:view).
  • Their team-role defaults for every team they’re on.
  • The new custom binding (aiTools:manage at org scope).

Role bindings at /settings/role-bindings

The bindings page is a deep table: every active RoleBinding row in the org. Filter by user, role, scope, or scope target. The most common admin questions: The page is the answer to “who can do what in this org.” Every change records an audit log row.

How permissions resolve at request time

A request hitting any *:manage-gated procedure flows through checkOrganizationPermission (or checkTeamPermission for team-scoped procs), which:
  1. Walks the user’s role bindings.
  2. Builds the effective permission set as the union of: org-role defaults + every team-role default the user has + every custom-role permission via active bindings.
  3. Returns true if the requested permission is in the set.
The resolver is per-request. Permission changes take effect on the next request from the user, there’s no session-level cache. JWT TTL (1h) is the upper bound on how long a stale grant can leak via existing tokens.

Where to next

Last modified on August 15, 2026