What it is
OpenFGA implements Relationship-based Access Control (ReBAC) from Google’s Zanzibar paper. Permissions are derived from relationships between users, groups, and resources — authorization logic lives outside application code.
OpenFGA Server = database server
Store = individual database (model + tuples)
Core syntax
Tuple format: object:id#relation@user:id
document:roadmap#viewer@user:alice // direct user
document:roadmap#viewer@group:eng#member // all members of a group
# operator: group#member means “anyone who has a member relationship with a group” — not the group entity itself. Without #, it’s ambiguous who in the group gets access.
Model patterns
type document
relations
define owner: [user]
define editor: [user] or owner
define viewer: [user, group#member] or editor or viewer from parentor= union (either condition)and= intersection (both required)from parent= hierarchical inheritance
Authorization flow
Request → App DB lookup (what sets does this user/resource belong to?)
→ OpenFGA Check(user, relation, object) → { allowed: true/false }
→ Return data or 403
Docker setup
services:
migrate:
image: openfga/openfga:v1.11.5
command: migrate # run first
openfga:
image: openfga/openfga:v1.11.5
command: run
depends_on:
migrate:
condition: service_completed_successfully
ports:
- "8080:8080" # HTTP API
- "3000:3000" # Playground UI (disable in prod)Auth
Local dev: disable auth entirely. Production: preshared key via OPENFGA_AUTHN_PRESHARED_KEYS.
Warning
Store
OPENFGA_AUTHN_PRESHARED_KEYSin Kubernetes Secrets — never commit auth keys to code.
Production notes
Warning
Production checklist — use PostgreSQL (not SQLite), network-isolate the server, cache
Checkresults client-side, and clean up tuples on deletion (stale tuples accumulate silently).
See also
- channel-closure-select — handling closed channels from OpenFGA’s StreamedListObjects API
- token-vs-api-key-auth — auth header formats for external integrations