English for OpenFGA Developers
Vocabulary for developers implementing fine-grained authorization with OpenFGA — relationship tuples, authorization models, type definitions, and the Check API — for teams discussing Zanzibar-style permissions in English.
OpenFGA is an open-source, fine-grained authorization engine modeled on Google’s Zanzibar paper — instead of hardcoding “if role == admin” checks throughout your codebase, you define an authorization model and store permissions as relationship tuples that a central service evaluates. The vocabulary is unfamiliar even to experienced backend developers because it borrows relational and graph-theory language rather than typical role-based-access terms. Here’s what your team needs to discuss it precisely.
The Authorization Model
Authorization model — the schema that defines what object types exist (documents, folders, teams) and what relations are possible between them (owner, editor, viewer); it’s versioned and evaluated against every permission check. “We shipped a new authorization model version that adds a ‘reviewer’ relation on documents — old tuples still validate against it because we kept the existing relations intact.”
Type definition — the part of the model describing one object type and the relations it supports, including how those relations can be inherited (e.g., editors of a folder are automatically editors of documents inside it). “The folder type definition says editor access cascades to every document inside it, so we don’t have to write a separate tuple for each file.”
Relation — a named connection between a user (or user set) and an object, like “owner,” “viewer,” or “member” — the building block every permission check resolves against. “Before adding a new relation, check whether an existing one already covers the use case — every new relation adds a maintenance surface to the model.”
Tuples and Checks
Relationship Tuple
A relationship tuple is a stored fact — user:anna is owner of document:budget-2026 — that represents one concrete grant of access.
“When a user is added to a team, we write a relationship tuple linking them as a member — that single write is what unlocks every resource the team can access.”
Check API
The Check API answers a single yes/no question — “can this user perform this action on this object?” — by resolving the authorization model against the stored tuples.
“Every ‘can edit’ button in the UI calls the Check API first — we never infer permissions client-side from cached role data.”
Contextual Tuple
A contextual tuple is a temporary tuple supplied only for the duration of a single check, useful for evaluating hypothetical or time-bound access without writing it to the store.
“We used a contextual tuple to test what would happen if this user were added to the ‘legal’ team, without actually granting them access yet.”
List Objects
ListObjects is the API call that returns every object a user has a given relation to — the reverse of Check, used for filtering a list view down to what a user is allowed to see.
“The dashboard calls ListObjects once to get every document the user can view, instead of running a Check call per row.”
Modeling Patterns
Direct relationship — a relation granted explicitly to a specific user, as opposed to one inherited through a group or parent object.
“We modeled team ownership as a direct relationship so revoking one person’s access doesn’t accidentally affect the rest of the team.”
Relationship inheritance (userset) — expressing that membership in one relation automatically grants another, like “any editor of the parent folder is also an editor of this document.”
“Relationship inheritance from folder to document is what lets us avoid writing a tuple for every single file when someone joins a team.”
Explaining OpenFGA to a Team
| Situation | Phrase |
|---|---|
| Justifying it over hardcoded roles | ”Our permission logic outgrew simple role checks — fine-grained, relationship-based authorization scales better once we have per-document sharing.” |
| Explaining a modeling decision | ”We’re using a userset for folder-to-document inheritance so shared-folder access doesn’t require a tuple write per file.” |
| Describing a performance choice | ”We call ListObjects once for the whole list view instead of a Check per row — that’s the pattern OpenFGA recommends for filtered lists.” |
| Discussing model versioning | ”Old tuples still resolve correctly against the new model version, so this migration doesn’t need a backfill.” |
Common Mistakes
- Confusing a relation (a named connection type in the model) with a relationship tuple (one concrete instance of that connection) — the model defines what’s possible, tuples record what’s actually granted.
- Running a Check call per item in a list instead of using ListObjects — this causes N+1-style authorization calls that don’t scale.
- Forgetting that contextual tuples are check-time only — they don’t persist, so relying on them for actual access control is a bug, not a feature.
Practice Exercise
- Explain, in two sentences, the difference between a relationship tuple and an authorization model to a teammate new to Zanzibar-style systems.
- Write a short PR description for adding a “reviewer” relation to the document type and the tuples needed to grant it.
- Draft a message explaining why ListObjects is the right choice for populating a filtered document list, instead of per-row Check calls.