Grant access to a resource
Do this when one person needs access to one object — a colleague who should be able to edit a single agent, or an agent that needs to read a specific skill. Grants are per object and per permission bit. Do not do this to give someone broad access to everything in a workspace; add them as a workspace member or admin instead. And do not do this to control what a running agent may do — tool restrictions, budgets and approvals are policy rules, not graph grants. See set a budget and authorize a tool call.Prerequisites
-
A graph backend enabled:
ACCESS_CONTROL_BACKEND=openfga. The setting defaults todisabled, and with it disabled every write here returns HTTP 503 and the permission service allows everything. Which stack you started decides whether it is on:If you are onmake up, switch tomake up-devor set the variable and run OpenFGA yourself before continuing. -
You are a workspace admin. Every
/v1/access-controlendpoint requires it. - The subject is already a member of your workspace, and the object already exists in it. Both are checked before the tuple is written.
- Read the AgentArea model — in particular that the three permission bits are independent.
API=http://localhost:8000 and a bearer token in $TOKEN.
Steps
1. Confirm the graph is on
enabled: false means no graph backend is configured — stop here and set
ACCESS_CONTROL_BACKEND before continuing.
2. Choose the relation
The relation you send is mapped onto one of three grant relations on the resource. Pick by what the subject needs to do:
Four legacy names still resolve, so older scripts keep working:
viewers and
connectors map to reader, editors to writer, and owners and operators
to manager.
The bits do not imply each other. A subject with only manager cannot read
the resource. To give somebody full access, write all three.
3. Write the grant
namespace is one of Agent, MCPServer, Skill or SkillCollection. It
selects the repository used to confirm the object belongs to your workspace; the
tuple itself is always written against resource:<object>, because all four
kinds are one generic type in the graph.
subject_id takes two shapes. Use User:<user_id> for a person. Use
Agent:<agent_uuid> to let one agent reach a resource in its own right — that
agent must also be in your workspace.
A successful write returns HTTP 201 and {"ok": true}. Writes are idempotent, so
repeating one is safe.
4. Repeat for each bit you need
DELETE /v1/access-control/relationships. It
returns HTTP 204.
Verify
Ask the graph directly.relation accepts the same verbs the application uses,
and they are mapped onto the underlying bit:
allowed, effective_relation, verb and a paths array.
resource_kind is one of skill, collection, mcp or agent.
You can also list what has been written:
Troubleshooting
403 Only a workspace admin may modify the authorization graph. Every
endpoint under /v1/access-control requires workspace admin, including the read
and check endpoints. Being the resource’s owner is not enough.
403 Agent:<id> not found in your workspace. The object id is wrong, belongs
to another workspace, or you are sending it with the wrong namespace. The
lookup uses the namespace to pick the repository, so an MCP server id sent with
"namespace": "Agent" fails this way.
403 Subject user is not in your workspace. Add the person to the workspace
first through POST /v1/workspaces/{workspace_id}/invitations. Membership is
resolved from the workspace owner plus the membership table, so a user who has
been invited but has not accepted is not yet grantable.
422 Unsupported relation for a resource grant. You sent something outside
the accepted set. Use reader, writer or manager.
422 Group (subject_set) grants are managed via project/role, not the explorer. This endpoint writes direct grants only. Bundled or group-scoped
access goes through role and role_assignment objects — see
model a custom relation.
503 Graph authorization is disabled or Graph authorization write failed.
The first means ACCESS_CONTROL_BACKEND is disabled. The second means OpenFGA
was reachable but rejected or dropped the write; the API deliberately does not
fall back to allowing the operation, so check the OpenFGA container before
retrying.
The grant exists and the user still cannot read. Almost always the
independent-bits rule. Check all three separately — read, edit and manage
each need their own tuple, and a manager grant confers neither of the others.
The grant exists and nothing changed in the product. Only a handful of API
call sites consult the graph today: agent, skill and MCP server edit and delete,
model instance delete, and registered-client use. List and read endpoints are
scoped by workspace in the database and are not graph-filtered, so a grant will
not make a resource appear or disappear from a list.
Related
- The AgentArea model — the types and inheritance behind these tuples.
- Model a custom relation — when direct grants are not enough.
- Review the audit trail — note that grant changes are not recorded there.