Table of Contents
OpenFGA Authorization Model
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.
Why it exists
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.
- Model = the rules (the shape).
- Tuples = the data (the facts).
- Together = the graph OpenFGA walks to answer a Check.
What it contains
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.
Two kinds of relation
A relation can be direct or computed.
- Direct: filled in by a tuple. Written with square brackets showing which types are allowed.
define owner: [user]means “a user can be assigned as owner”. - Computed: worked out from other relations, no tuple needed.
define editor: [user] or ownermeans “an editor, or anyone who is already an owner”.
Relation operators
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.
Type restrictions
Direct relations say which types are allowed. This can also include:
- A single type:
[user] - A userset:
[group#member]— every member of a group. - A wildcard:
[user:*]— every user (public access).
<note> Type restrictions keep the model safe. You cannot assign a type that the relation does not allow. </note>
Conditions (ABAC)
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”.
Two syntaxes
- DSL: the human-friendly form you write and read. Shown in all examples here.
- JSON: the form the API stores. The DSL compiles down to JSON.
They describe the same model.
Versioning
Each time you write a model, OpenFGA saves it as a new, immutable version with its own model ID. Old versions stay. This means:
- You can change rules without breaking old tuples.
- A Check can be pinned to a specific model version.
- You get a full history of your rules.
Example
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.
How it fits
Input → Process → Output:
- Input: you write the model once in DSL.
- Process: OpenFGA compiles it, versions it, and uses it to guide every Check.
- Output: a stable set of rules that tuples plug into.
