agentarea-platform/libs/common/agentarea_common/rebac/openfga/model.fga; the deployable payload
authorization-model.json next to it is generated from it and ships in the image.
Synopsis
resource:<uuid>#reader@User:<id>.
Fields
Workspace
role
A role is a bag of independent bits. Each enabled bit must be written for both
User:* and Agent:*; a bit written only for User:* denies agent assignees.
role_assignment
Attach each assignment to exactly one object; attaching one assignment to several
objects amplifies its bits across all of them.
project
resource
Agents, skills, MCP servers and registered clients are all
resource:<uuid>.
Which kind a resource is lives in the database, not the graph.
Values
Permission bits
can_read, can_write and can_manage are independent. None implies another. A
role granting only can_write yields can_write: true with can_read: false
and can_manage: false.
Verb to bit — permission service
Applied byrequire_permission and the DI-resolved permission service.
A verb outside this map is denied and logged at warning level.
Verb to bit — relationship explorer
Applied by the/v1/workspaces/{workspace}/access-control check endpoint. Note the absence of update.
A value that is neither a mapped verb nor one of the three bits returns
allowed: false without querying the graph.
Relation aliases accepted on write
The explorer write endpoint maps a submitted relation onto a resource grant.
Anything else is rejected. A
subject_set (group) body is rejected; bundled
access goes through role and role_assignment.
Namespaces accepted by the explorer
The namespace selects a repository for that check only. The tuple written or
checked is always against
resource:<object>.
Subject forms accepted on write
Seeded tuples
On workspace creation:
On governed resource creation:
The root project id is the workspace id suffixed with
-root. Both writers are
idempotent; an “already exists” response is treated as success.
Enforcement
Invariants the graph cannot express, enforced by the writer instead: one
workspace and one parent per project, one project per resource, same-workspace
edges, an acyclic project graph, one object per
role_assignment, and resource
kind resolved from the database.
Defaults and overrides
AGENTAREA_AUTHZ_BACKEND accepts only openfga; any other value fails startup.
docker-compose.dev.yaml and the Helm chart both set BOOTSTRAP and
APPLY_MODEL to true. The applied model is the one packaged with the image,
so the relations the code checks always exist in it; nothing is mounted.
AGENTAREA_AUTHZ_FGA_MODEL_PATH is for a deployment that extends the model. It
names a model built with OpenFGA modular models: an fga.mod listing the
packaged model.fga plus your own module, transformed with fga model transform --file fga.mod. The process refuses to start when that model drops or redefines
any packaged type, relation or condition, and names each one. Additions are yours.
With APPLY_MODEL enabled the model’s id is used for the process lifetime. With
it disabled, AGENTAREA_AUTHZ_FGA_MODEL_ID is used and no model is written.
Bootstrap compares candidate models by normalized content ignoring ids, so an
unchanged model is reused rather than rewritten. When several processes race a
store create, all converge on the earliest store with that name.
Example
Grant a write-only role bundle on a project, and confirm the bits do not roll up:Related
Policy rule syntax
The other authorization surface, which governs tool invocation
Limits
Timeouts and pagination on the graph client
Errors
The 403 and 503 responses these checks produce
The AgentArea model
The reasoning behind the type set