Google's 2019 Zanzibar paper described the system behind permissions in Drive, Calendar, YouTube and more — a single global service answering one question billions of times a second: authz may this subject perform this action on this object?
Its core idea is disarmingly small. Permissions are not flags on rows; they are relationships stored as tuplesZanzibarA stored relationship fact of the form object#relation@subject, e.g. document:readme#viewer@user:foo. The atomic unit of ReBAC. of the shape object#relation@subject. Membership, ownership, sharing — all of it is just edges in a graph.
# relationships are facts, written as tuples
document:q3-plan#viewer@user:foo
document:q3-plan#editor@group:finance#member # a whole group, by reference
group:finance#member@user:foo
The power comes from userset rewritesZanzibarRules that compute one relation from others ('editors are also viewers', 'inherit the parent's viewers'), letting a Check traverse the graph.: a relation can be computed from others. "Editors are also viewers." "A folder's viewers include its parent's viewers." These rules let a Check traverse the graph to resolve a permission no single tuple states outright — and run backwards, so LookupResources answers which objects a user can reach. Consistency tokens ("zookies"Zanzibar consistencyA token captured at write time. Passing it to a later Check guarantees the answer reflects that write — preventing stale reads of revoked access.) guarantee a Check reflects a just-written share, defeating the "new enemy" problem of stale reads leaking revoked access.
Zanzibar is a paper, not a product — so it has more than one open implementation, and Frauthy treats the store as pluggable:
Default backend
SpiceDB
AuthZed's implementation. Typed schema language, the ZedToken consistency handle, a Watch stream. Frauthy's default — and what Frauthy Script targets first.
Alternate backend
Ory Keto
Ory's implementation, configured through the Ory Permission Language. A first-class Frauthy target for teams already inside the Ory stack — selected with one line.
Both speak the same Zanzibar grammar, so the same Frauthy schema compiles to either (Author once, compile anywhere). A SpiceDB schema reads like a model of your domain:
definition user {}
definition document {
relation viewer: user
relation editor: user
permission edit = editor
permission view = viewer + editor # editors can view too
}writing facts & asking questions · the Check API
# 1 · write a relationship (a fact)
WriteRelationships:
document:q3-plan#editor@group:finance#member
# 2 · ask: may foo view the doc? (foo is only a finance member)
CheckPermission:
resource = document:q3-plan
permission = view
subject = user:foo
consistency = at_least_as_fresh(ZedToken) # no stale reads
# → PERMISSIONSHIP_HAS_PERMISSION ✓ (resolved through the group)
That answer isn't stored anywhere — it's computed by walking the graph at query time. Nobody wrote "foo can view q3-plan"; the Check derives it:
- 01subject
Start with the subject
user:foo is asking to view the document.
user:foo - 02membership
Resolve group membership
Foo belongs to group:finance#member.
foo ∈ group:finance#member - 03relation
Follow the relation
Finance members are document editors.
document#editor - 04rewrite
Apply the userset rewrite
view includes viewer and editor, so every editor may view.
view = viewer + editor - 05decision
Allow
The graph proves access even though no single tuple states it.
ALLOW
What these give you: fine-grained, relationship-based authorization that composes across every service from one source of truth — answering both "may they?" and "which ones?". What they ask of you: design a schema, keep relationships in sync, feed in verified identities from somewhere, and wire a Check into every call site — separately, per store, per language. That wiring is the seam from OIDC.