RBAC Reference
Role-Based Access Control in Solace Agent Mesh is allowlist only. A user is granted scopes through roles; if a required scope is not in the user's granted set, the request is denied.
This page is the reference for the scope grammar, the platform-shipped scope catalog, and the authoring surfaces. To take a permissive deployment to least-privilege step by step, see Enabling Role-Based Access Control (RBAC).
Scope Format
Every scope is three colon-delimited segments:
<category>:<resource>:<verb>
| Segment | Meaning |
|---|---|
<category>
|
Singular family name — for example, rbac, agent, agent_builder, workflow, workflow_builder, connector, entrypoint, tool, evaluation, analytics. |
<resource>
|
A specific instance id, * (any instance), or the literal _ (no specific instance — for collection-level or flat-feature actions). |
<verb>
|
The action. Standard set: read, create, update, delete, deploy, invoke, subscribe, share, test, assign. Tool-execution verbs (for example, request, transcribe) are an exception. |
Three valid values for the resource segment:
| Form | Meaning | Example |
|---|---|---|
<id>
|
This specific instance (YAML-defined resources use the authored name as their id) | agent:hr-bot:invoke
|
*
|
Any instance | agent_builder:*:update
|
_
|
No instance — collection-level or flat-feature | agent_builder:_:create, rbac:_:read |
*:*:* is the superadmin grant. Inside segments 1-3, * works like a shell glob within that segment. The matcher also accepts the bare * (single token) as a shorthand for *:*:*.
Common Scopes
The tables that follow list a non-exhaustive selection. Per-instance scopes (for example, agent:<id>:invoke) are derived from the resource being addressed; the runtime maps each component to the exact invoke scope a caller must hold (see the three-row rule that follows).
Flat Platform Features
| Scope | Gates |
|---|---|
rbac:_:read / :_:create / :_:update / :_:delete |
RBAC management surface |
rbac:*:*
|
All RBAC operations |
evaluation:_:read / :_:create / :_:update / :_:delete / :_:invoke |
Evaluation runs and configuration |
analytics:_:read
|
Admin observability dashboard |
analytics:_:read_content
|
Same plus per-user prompt/feedback content |
tool:_:read
|
Read the tool catalog |
deployment:_:read
|
View deployment audit log |
builder:_:use
|
Cross-builder UI capability gate |
profile_provider:_:update
|
Configure the identity profile-provider toolset |
notify:_:send
|
Send a notification to your own inbox (default user grant) |
notify:_:send_others / :_:read_others |
Post to, or read, another user's inbox (elevated admin/support) |
Resource Families with Collection and Category-Wide Scopes
These management families support a collection-level create scope plus category-wide (*) scopes for the remaining verbs. Enforcement is at the all-instances level: a grant applies to every instance in the family. Per-instance (<id>) scoping for these families is not enforced — the only family with true per-instance access is agent invocation, described under Runtime Agent-to-Agent (A2A) Access in the following section.
| Collection-level (create) | Category-wide (read/update/delete, and so on) |
|---|---|
agent_builder:_:create
|
agent_builder:*:read / :update / :delete / :deploy / :test |
workflow_builder:_:create
|
workflow_builder:*:read / :update / :delete / :deploy |
connector:_:create
|
connector:*:read / :update / :delete |
entrypoint:_:create
|
entrypoint:*:read / :update / :delete / :deploy |
model_config:_:create
|
model_config:*:read / :update / :delete |
skill:_:create
|
skill:*:read / :update / :delete |
toolset:_:create
|
toolset:*:read / :update / :delete |
A single wildcard grant covers a whole family: connector:*:* authorizes both connector:_:create and every category-wide operation.
Projects and prompts are governed by resource ownership plus per-resource ACL sharing, not per-instance RBAC scopes. The catalog retains project:_:share and prompt:_:share capability scopes, but they are inert — no longer enforced. Sharing a project or prompt you own requires no scope: the handlers enforce ownership, so only the resource owner can manage its shares.
Runtime Agent-to-Agent (A2A) Access
| Scope | Gates |
|---|---|
agent:<id>:invoke
|
Invoke a specific agent over A2A — both direct user submission and peer routing |
agent:*:invoke
|
Invoke any agent (delegating role) |
workflow:<id>:invoke
|
Invoke a specific deployed workflow over A2A |
workflow:*:invoke
|
Invoke any deployed workflow |
tool:email:send
|
Send email through the send_email tool (server-side SMTP credentials) |
tool:datadog_logs:invoke
|
Query Datadog logs through the datadog_logs tool (admin observability) |
Built-in tools otherwise require no scopes: holding agent:<id>:invoke for an agent implies access to every tool configured on it, including schedule_task (the scheduled invocation re-authorizes against the creator's invoke scopes when it fires). The two preceding scopes (plus notify:_:send) are the deliberate exceptions — capabilities with externalized side effects that stay individually grantable. Custom tools (Secure Tool Runtime packages, Model Context Protocol (MCP), OpenAPI, connectors) can still declare their own required_scopes, which are enforced as before.
Which invoke scope a component requires (the three-row rule):
| Component | Required scope | <id> is |
|---|---|---|
| Deployed workflow | workflow:<id>:invoke
|
the workflow's dashed UUID |
| Platform-deployed agent | agent:<id>:invoke
|
the agent's dashed UUID |
| YAML-authored / built-in agent | agent:<name>:invoke
|
the authored name |
Segment 2 is always the dashed UUID (019e47f4-2be0-75d8-828e-77a0d1d9221f), never the underscored broker name the component is addressed by on the wire (workflow_019e47f4_2be0_...). agent:*:invoke covers the agent category only — it does not cover deployed workflows. A role that must run workflows needs workflow:*:invoke (or a per-workflow workflow:<id>:invoke).
Authoring pattern for roles that run workflows: grant workflow:*:invoke (or the per-UUID scope) plus agent:*:invoke. A workflow's directed acyclic graph (DAG) delegates to child agents on each hop, and each hop is authorized independently against the caller's scopes, so the agent wildcard keeps those child hops from being denied. Workflow grants are not currently transitive to child hops, which is why the extra agent:*:invoke is required today; a role that keeps the wildcard remains correct if that changes.
Authoring Surfaces
Two authoring surfaces, both writing into the same composed role/assignment graph.
YAML Role Files
These role files are operator-managed on disk and loaded at entrypoint and platform startup from ROLE_DEFINITIONS_PATH and USER_ROLES_PATH. Use them for the bootstrap admin and for stable, change-controlled role definitions.
# roles.yaml
roles:
rbac_admin:
description: "Manage RBAC. Cannot grant scopes the admin themselves do not hold."
scopes:
- "rbac:*:*"
agent_developer:
description: "Build and deploy agents."
scopes:
- "agent_builder:*:*"
- "tool:_:read"
analyst:
description: "Run agents and use the chat surface."
scopes:
- "agent:*:invoke"# users.yaml
users:
alice@example.com:
roles: [rbac_admin]
bob@example.com:
roles: [analyst]
Email identities are lowercased for matching; other identity forms (OIDC sub) are case-sensitive.
Note the direction of this operator surface: users.yaml is keyed by user, mapping each identity to the roles it holds. The declarative spec.users shown in the following section is the inverse — keyed by role, listing the identities granted that role. They write into the same composed graph from opposite ends.
sam config apply
Two declarative-configuration kinds manage the same surface from a Git-backed repository: rbacRole and rbacClaimMapping. The lifecycle matches the other declarative kinds (skills, connectors, toolsets) — see Managing Configuration as Code (Early Access) for the sam config plan / apply / pull workflow.
A role grant is declared inline on the role, via a spec.users list of identities:
kind: rbacRole
name: analyst
spec:
scopes:
- "agent:*:invoke"
- "tool:*:*"
users:
- alice@example.com
- bob@example.com
There is no standalone assignment kind. Each spec.users entry becomes one platform grant at apply time; removing a user from the list retires that grant (behind --prune). A repo that still keeps grants under rbac/assignments/ (or a manifest declaring rbacAssignments) is rejected with a message pointing at spec.users — move each grant onto its role file's users: list and delete the rbac/assignments/ directory. Group-to-role mapping via spec.groups is not currently supported; use rbacClaimMapping for claim-driven access.
The YAML and database halves are disjoint at the foreign-key level — a database role cannot inherit a YAML role, and a database assignment cannot reference a YAML role. The Platform service refuses both at write time.
IdP Claim Mapping
Roles can be sourced from OIDC group claims rather than (or in addition to) explicit user entries:
authorization_service:
type: default_rbac
idp_claims_config:
claim_key: groups
mappings:
"/sam-admins": [rbac_admin]
"/sam-analysts": [analyst]
A user's resolved roles are the union of YAML user-roles, IdP claim mappings, and database-managed assignments.
Diagnosing a Denial
When the entrypoint logs agent delegation denied or returns 403 insufficient scope: X required:
-
Confirm the user's resolved scopes by calling
GET /api/v1/user/capabilities?scopes=<scope>on the entrypoint. -
Cross-check the role assignments in the Platform service.
-
Verify the IdP claim if the user is sourced via
idp_claims_config.
Scope matching is wildcard-aware per segment: a * in a granted scope matches any value in that position. Wildcard matching is what makes per-instance access work — a grant of agent:*:invoke covers a check against any specific agent:<id>:invoke, and workflow:*:invoke covers any workflow:<id>:invoke. The category (segment 1) still has to match: agent:*:invoke does not cover a workflow:<id>:invoke check, so a role that runs workflows needs the workflow: grant as well (see the preceding three-row rule). The management families are category-wide: agent_builder:*:* covers the collection-level agent_builder:_:create and every category-wide verb (agent_builder:*:read / :update / …) in one grant, and *:*:* (or the bare *) authorizes everything. The _ sentinel is a literal value: a required rbac:_:read is covered by a grant of rbac:_:read or rbac:*:read, but not by rbac:foo:read. Every scope you author must have all three segments — the family-wide grant is agent_builder:*:*, not agent_builder:* — with the single bare * (superadmin) the only exception.
Matching is case-sensitive. The instance id in segment 2 of a per-instance scope carries the exact casing of the underlying object. For YAML-defined or built-in resources the id is the authored name, which may be mixed-case — for example an agent named Orchestrator. A grant of agent:orchestrator:invoke (lowercase) does not authorize a check against agent:Orchestrator:invoke (capital O). If your IdP claim mapper or role-management tooling normalizes scope strings (for example, lowercases everything), make sure the id in each grant matches the live object's case exactly. A common pitfall is an IdP-mapped group claim that lowercases the scope, granted to a user whose target agent has a mixed-case name. (Platform-deployed resources use a generated lowercase id, so this only affects name-derived ids.)