====== OpenFGA Relationship Tuples ======
A **relationship tuple** is one small fact about who is connected to what. It is
the //data// in OpenFGA. The [[security:authorization:openfga:authorization-model|authorization model]]
defines the shape of the rules; tuples fill in the real facts.
* Model = the rules (the shape).
* Tuples = the data (the facts).
* Together = the graph the Check API walks.
===== Why they exist =====
The model alone answers nothing. It only says a document //can// have an owner. A
tuple says //who// the owner actually is. You need thousands or millions of these
facts to describe your real users, groups, and objects.
===== What a tuple looks like =====
Every tuple has three parts, plus an optional condition.
^ Part ^ Meaning ^ Example ^
| **user** | who or what the fact is about | ''user:anne'' |
| **relation** | the named link (must exist in the model) | ''owner'' |
| **object** | the thing being accessed (''type:id'') | ''document:budget'' |
Written together:
user:anne owner document:budget
Read it as: "Anne is the owner of the budget document."
===== The three fields in detail =====
==== user ====
The ''user'' field is flexible. It can be:
* **An object**: ''user:anne'' — one specific subject.
* **A userset**: ''group:eng#member'' — //every member// of the eng group. \\ This is how you grant access to a whole group at once.
* **A wildcard**: ''user:*'' — //every// user of that type (public access).
==== relation ====
The name of the link, like ''owner'', ''editor'', or ''viewer''. It **must** be a
relation that exists in the model for that object's type. You cannot invent one.
==== object ====
The target, always in ''type:id'' form, like ''document:budget'' or
''organization:acme''. The type must exist in the model.
===== Examples =====
user:anne owner document:budget
user:bob viewer document:budget
group:eng#member viewer document:roadmap
folder:finance parent document:budget
user:* viewer document:public-notice
Notice the fourth line: the ''user'' is itself an object (''folder:finance''). This
links a document to its parent folder, so access can flow along that link.
===== Conditional tuples (ABAC) =====
A tuple can carry a **condition** and some context. The grant only counts if the
condition is true. For example, a tuple might say "Anne is a viewer //only if the
current time is during work hours//". This mixes attribute checks into the data.
===== Writing and deleting tuples =====
You change tuples through the **Write API**.
* **Write**: add a new fact (Anne becomes an owner).
* **Delete**: remove a fact (Anne is no longer an owner).
Tuples are usually kept in sync with your main database. A common pattern is
**CDC** (Change Data Capture): when a row changes in your database, a matching
tuple is written or deleted in OpenFGA automatically.
===== Contextual tuples =====
Some facts are not stored. You can pass **contextual tuples** inside a single
Check call. They exist only for that one question and are never saved.
Use contextual tuples for facts you know at request time but do not want to
store, such as the user's current department passed in from a request header.
===== How they fit =====
Input → Process → Output:
* **Input**: your app (or CDC) writes tuples as facts change.
* **Process**: on a Check, OpenFGA walks these tuples using the model rules.
* **Output**: an ''allowed: true'' or ''allowed: false'' answer.
===== See also =====
* [[security:authorization:openfga:store|Store]]
* [[security:authorization:openfga:authorization-model|Authorization model]]
* [[https://openfga.dev/docs/interacting/managing-relationships-between-objects|Managing relationships (tuples)]]
* [[https://openfga.dev/docs/modeling/token-claims-contextual-tuples|Contextual tuples]]