An authorization model is the set of rules. It defines what types of things exist and what relations can hold between them. It is the schema for your permissions.
It holds only the shape of the rules. It does not hold real users or real data — that is what relationship tuples are for.
Your app needs an agreed set of rules before it can answer any question. The model is that agreement. It says things like “a document has an owner” and “an editor can also view”. Once the model is set, tuples fill in the real facts, and the Check API uses both together.
Two building blocks.
| Block | What it is |
|---|---|
| Type | A kind of object: user, document, folder, organization. |
| Relation | A named link on a type: owner, editor, viewer, member. |
Each type lists the relations that can point to it.
A relation can be direct or computed.
define owner: [user] means “a user can be assigned as owner”.define editor: [user] or owner means “an editor, or anyone who is already an owner”.Computed relations use four operators.
| Operator | Meaning | Example |
|---|---|---|
or (union) | this or that | editor: [user] or owner |
and (intersection) | this and that | can_edit: editor and member |
but not (exclusion) | this but not that | viewer: editor but not banned |
from (tuple-to-userset) | inherit through another relation | viewer: viewer from parent |
The from operator is the key to ReBAC. viewer from parent means “you are a
viewer of this document if you are a viewer of its parent folder”. Access flows
along the link.
Direct relations say which types are allowed. This can also include:
[user][group#member] — every member of a group.[user:*] — every user (public access).<note> Type restrictions keep the model safe. You cannot assign a type that the relation does not allow. </note>
A relation can carry a condition: a small rule that must also be true. This mixes attribute checks into the model. Example: a grant that only applies “if the amount is under 500” or “only during work hours”.
They describe the same model.
Each time you write a model, OpenFGA saves it as a new, immutable version with its own model ID. Old versions stay. This means:
A classic document / folder model in DSL:
model
schema 1.1
type user
type folder
relations
define viewer: [user]
type document
relations
define parent: [folder]
define owner: [user]
define editor: [user] or owner
define viewer: [user] or editor or viewer from parent
Read the last line as: you can view a document if you are directly a viewer, or an editor, or a viewer of its parent folder.
Input → Process → Output: