RBAC & Scope System Design¶
The registry uses a two-layer authorization model: scopes control which API endpoints a user can call, and ACL controls which specific resources they can see or modify within those endpoints. This model is grounded in enterprise AI governance principles and implemented through the Jarvis Governed AI Layer.
The canonical source of truth for scope definitions is registry-pkgs/src/registry_pkgs/scopes.yml. The enforcement logic lives in registry/src/registry/middleware/rbac.py.
Two-Layer Authorization¶
Scopes are coarse-grained (endpoint access). ACL is fine-grained (per-resource access). Both must pass for a request to succeed on protected resources.
Layer 1 — ScopePermissionMiddleware: loaded from scopes.yml at startup, checks whether the user's token includes the scope required for the requested endpoint/method. Returns 403 immediately if not.
Layer 2 — ACL (resource-level): enforced inside the service layer via access_control_service.py, checks whether the user has VIEW, EDIT, or DELETE permission on the specific resource being accessed.
Roles and Their Scopes¶
Four built-in roles are defined via IdP group mappings in scopes.yml under group_mappings.
| Role | Group Name | Description |
|---|---|---|
| Admin | jarvis-registry-admin | Full access including system ops and ACL management |
| Power User | jarvis-registry-power-user | Full CRUD on all resources + share; no system ops |
| User | jarvis-registry-user | CRUD on servers/agents/federations; no sharing or ACL write |
| Read-Only | jarvis-registry-read-only | Read-only access to servers, agents, federations |
Role-to-scope mapping is defined entirely in scopes.yml — no code changes needed to adjust which scopes a role carries.
Scope Catalog¶
Each scope maps to one or more API endpoints. ScopePermissionMiddleware compiles these at startup and enforces them on every authenticated request.
| Scope | What It Covers |
|---|---|
servers-read | List/get MCP servers, check connections, get tools |
server-write | Register, update, delete, toggle MCP servers |
agents-read | List/get A2A agents, skills, health, well-known card |
agents-write | Create, update, delete, toggle A2A agents, sync well-known |
federations-read | List/get federations |
federations-write | Create, update, delete, sync federations |
federations-share | Manage ACL on federation resources |
servers-share | Manage ACL on MCP server resources |
agents-share | Manage ACL on A2A agent resources |
acl-read | Search principals, read resource permissions |
acl-write | Update resource permissions |
user-read | Auth info, tokens, search, MCP connection/OAuth management |
system-ops | Admin stats, token admin, AgentCore runtime sync |
mcp-proxy-ops | MCP proxy and session endpoints |
How Scopes Are Resolved¶
Scopes for an incoming request are resolved from the JWT token via effective_scopes_from_context():
- Explicit scopes in token — if the
scopeclaim is present (e.g., a down-scoped token), those scopes are used as-is. No group mappings are applied, preventing unintended privilege escalation. - Group-derived scopes — if no explicit scopes exist, the user's IdP groups are looked up in
group_mappingsand expanded into their scope list.
This lets agents and services operate with minimally scoped tokens while human users get their full role-based scope set from their IdP group membership.
Sharing and ACL Independence¶
Sharing scopes (federations-share, servers-share, agents-share) are intentionally decoupled:
- Sharing a federation does not cascade to the servers or agents it synced in. Each resource is shared independently.
- This means a user can have access to a federation definition without automatically gaining access to every resource it produced.
Adding or Modifying Scopes¶
All changes are made in scopes.yml — no code changes required:
- New endpoint: add an entry under the appropriate scope block with
action,method, andendpoint. - New role: add a key under
group_mappingsand list the scopes it should carry. - New scope: define a new top-level key with its endpoint rules, then reference it from roles in
group_mappings.
ScopePermissionMiddleware loads rules at application startup, so a service restart is required after any change to scopes.yml.