OpenFGA Best Practices
Use this skill to design and review OpenFGA models end to end: define types and relations, write tuples, derive can_* permissions, choose usersets and inheritance patterns, and validate behavior with .fga.yaml tests and CLI checks.
Quick Start Example
Minimal model:
model
schema 1.1
type user
type organization
relations
define admin: [user]
define member: [user] or admin
type document
relations
define organization: [organization]
define owner: [user]
define can_edit: owner or admin from organization
define can_view: can_edit or member from organization
Example tuples:
organization:acme#admin@user:alice
document:roadmap#organization@organization:acme
document:roadmap#owner@user:bob
Example test targets:
check that user:alice can view and edit document:roadmap
check that user:bob can edit their own document
list_users for document:roadmap#can_view
list_objects for documents user:alice can edit
How to Use
When a workflow step points to a rule ID, open the matching file in references/ for detailed guidance and examples.
Note: SDK references (sdk-*.md) are only needed for integration tasks — skip them during pure model authoring and testing.
Rule Index
Core
| File |
Description |
references/core-types.md |
Define types for entity classes |
references/core-relations.md |
Relations belong on object types |
references/core-tuples.md |
Relationship tuples as facts |
references/core-separation.md |
Model vs data separation |
references/core-schema-version.md |
Schema version |
Relations
| File |
Description |
references/relation-direct.md |
Direct relationships |
references/relation-indirect.md |
Indirect relationships with X from Y |
references/relation-concentric.md |
Concentric relationships |
references/relation-usersets.md |
Usersets for group-based access |
references/relation-conditions.md |
Conditional relationships |
references/relation-wildcards.md |
Wildcards for public access |
references/relation-wildcards-as-booleans.md |
Wildcards for boolean attributes |
Design
| File |
Description |
references/design-permissions.md |
Define permissions with can_ relations |
references/design-hierarchy.md |
Hierarchical structures |
references/design-organization.md |
Organization-level access |
references/design-create-on-parent.md |
Check create permissions on parent objects |
references/design-naming.md |
Naming conventions |
references/design-modules.md |
Modularize models (only when asked) |
Roles
| File |
Description |
references/roles-simple.md |
Simple static roles |
references/roles-static-combo.md |
Combining static and custom roles |
references/roles-assignments.md |
Role assignments for resource-specific roles |
references/roles-when-to-use.md |
When to use each role pattern |
Optimization
| File |
Description |
references/optimize-simplify.md |
Simplify models |
references/optimize-tuples.md |
Minimize tuple count |
references/optimize-type-restrictions.md |
Type restrictions |
rask-specific
| File |
Description |
references/grant-provenance.md |
Who GAVE a grant — the audit-join review procedure, and why a tuple cannot answer it |
Testing
| File |
Description |
references/test-fga-yaml.md |
Structure tests in .fga.yaml |
references/test-check-assertions.md |
Check assertions |
references/test-list-objects.md |
List objects tests |
references/test-list-users.md |
List users tests |
references/test-conditions.md |
Testing conditions |
references/test-cli.md |
OpenFGA CLI usage |
references/workflow-validate.md |
Always validate models |
SDKs (for integration tasks only)
| File |
Description |
references/sdk-javascript.md |
JavaScript/TypeScript SDK |
references/sdk-go.md |
Go SDK |
references/sdk-python.md |
Python SDK |
references/sdk-java.md |
Java SDK |
references/sdk-dotnet.md |
.NET SDK |
Recommended Workflow
Model the resource graph.
Define types, direct relations, inheritance edges, and can_* permissions.
Rules to check first: core-*, relation-*, design-permissions, design-hierarchy.
Add tuples and test intent.
Add representative tuples and cover expected behavior with check, list_objects, and list_users tests.
Rules to check next: core-tuples, test-fga-yaml, test-check-assertions, test-list-objects, test-list-users.
Review parent-child creation and deletion paths.
Verify each parent -> child edge has create permissions on the parent and that no child permission is directly grantable unless intended.
Rules to check: design-create-on-parent, relation-direct, design-permissions.
Simplify before removing schema.
Before deleting any type or relation, confirm it is not referenced by permissions, tuples, or tests.
If a simplification breaks a reference: restore the relation or update the model/tests, then re-run this step.
Rules to check: optimize-simplify, optimize-tuples, optimize-type-restrictions.
Validate the model.
Run:
fga model validate --file stores/<store>/model.fga
If validation fails: read the reported relation or type errors, fix the model, and re-run validation before continuing.
- Run the store tests.
Run:
fga model test --tests stores/<store>/store.fga.yaml
If tests fail: update tuples, assertions, or permission definitions, then re-run tests until all checks and list queries pass.
- Only then finalize delivery.
For touched stores, finish only after validation and tests are green.
Final rule to check:
workflow-validate.
Full Compiled Document
For the complete guide with all rules expanded: AGENTS.md
1---2name: openfga3description: OpenFGA authorization modeling best practices for defining types and relations, writing relationship tuples, deriving can_* permissions, applying type restrictions and usersets, and authoring .fga.yaml check/list_objects/list_users tests. Use when authoring, reviewing, or refactoring OpenFGA models, tuples, permissions, .fga files, .fga.yaml test files, or OpenFGA SDK integrations in JavaScript, TypeScript, Go, Python, Java, or .NET.4license: Apache-2.05---67# OpenFGA Best Practices89Use this skill to design and review OpenFGA models end to end: define types and relations, write tuples, derive `can_*` permissions, choose usersets and inheritance patterns, and validate behavior with `.fga.yaml` tests and CLI checks.1011## Quick Start Example1213Minimal model:1415```fga16model17 schema 1.11819type user2021type organization22 relations23 define admin: [user]24 define member: [user] or admin2526type document27 relations28 define organization: [organization]29 define owner: [user]30 define can_edit: owner or admin from organization31 define can_view: can_edit or member from organization32```3334Example tuples:3536```text37organization:acme#admin@user:alice38document:roadmap#organization@organization:acme39document:roadmap#owner@user:bob40```4142Example test targets:43- `check` that `user:alice` can view and edit `document:roadmap`44- `check` that `user:bob` can edit their own document45- `list_users` for `document:roadmap#can_view`46- `list_objects` for documents `user:alice` can edit4748## How to Use4950When a workflow step points to a rule ID, open the matching file in `references/` for detailed guidance and examples.5152**Note:** SDK references (`sdk-*.md`) are only needed for integration tasks — skip them during pure model authoring and testing.5354## Rule Index5556### Core57| File | Description |58|------|-------------|59| `references/core-types.md` | Define types for entity classes |60| `references/core-relations.md` | Relations belong on object types |61| `references/core-tuples.md` | Relationship tuples as facts |62| `references/core-separation.md` | Model vs data separation |63| `references/core-schema-version.md` | Schema version |6465### Relations66| File | Description |67|------|-------------|68| `references/relation-direct.md` | Direct relationships |69| `references/relation-indirect.md` | Indirect relationships with X from Y |70| `references/relation-concentric.md` | Concentric relationships |71| `references/relation-usersets.md` | Usersets for group-based access |72| `references/relation-conditions.md` | Conditional relationships |73| `references/relation-wildcards.md` | Wildcards for public access |74| `references/relation-wildcards-as-booleans.md` | Wildcards for boolean attributes |7576### Design77| File | Description |78|------|-------------|79| `references/design-permissions.md` | Define permissions with can_ relations |80| `references/design-hierarchy.md` | Hierarchical structures |81| `references/design-organization.md` | Organization-level access |82| `references/design-create-on-parent.md` | Check create permissions on parent objects |83| `references/design-naming.md` | Naming conventions |84| `references/design-modules.md` | Modularize models (only when asked) |8586### Roles87| File | Description |88|------|-------------|89| `references/roles-simple.md` | Simple static roles |90| `references/roles-static-combo.md` | Combining static and custom roles |91| `references/roles-assignments.md` | Role assignments for resource-specific roles |92| `references/roles-when-to-use.md` | When to use each role pattern |9394### Optimization95| File | Description |96|------|-------------|97| `references/optimize-simplify.md` | Simplify models |98| `references/optimize-tuples.md` | Minimize tuple count |99| `references/optimize-type-restrictions.md` | Type restrictions |100101### rask-specific102| File | Description |103|------|-------------|104| `references/grant-provenance.md` | Who GAVE a grant — the audit-join review procedure, and why a tuple cannot answer it |105106### Testing107| File | Description |108|------|-------------|109| `references/test-fga-yaml.md` | Structure tests in .fga.yaml |110| `references/test-check-assertions.md` | Check assertions |111| `references/test-list-objects.md` | List objects tests |112| `references/test-list-users.md` | List users tests |113| `references/test-conditions.md` | Testing conditions |114| `references/test-cli.md` | OpenFGA CLI usage |115| `references/workflow-validate.md` | Always validate models |116117### SDKs (for integration tasks only)118| File | Description |119|------|-------------|120| `references/sdk-javascript.md` | JavaScript/TypeScript SDK |121| `references/sdk-go.md` | Go SDK |122| `references/sdk-python.md` | Python SDK |123| `references/sdk-java.md` | Java SDK |124| `references/sdk-dotnet.md` | .NET SDK |125126## Recommended Workflow1271281. Model the resource graph.129 Define types, direct relations, inheritance edges, and `can_*` permissions.130 Rules to check first: `core-*`, `relation-*`, `design-permissions`, `design-hierarchy`.1311322. Add tuples and test intent.133 Add representative tuples and cover expected behavior with `check`, `list_objects`, and `list_users` tests.134 Rules to check next: `core-tuples`, `test-fga-yaml`, `test-check-assertions`, `test-list-objects`, `test-list-users`.1351363. Review parent-child creation and deletion paths.137 Verify each parent -> child edge has create permissions on the parent and that no child permission is directly grantable unless intended.138 Rules to check: `design-create-on-parent`, `relation-direct`, `design-permissions`.1391404. Simplify before removing schema.141 Before deleting any type or relation, confirm it is not referenced by permissions, tuples, or tests.142 If a simplification breaks a reference: restore the relation or update the model/tests, then re-run this step.143 Rules to check: `optimize-simplify`, `optimize-tuples`, `optimize-type-restrictions`.1441455. Validate the model.146 Run:147148```bash149fga model validate --file stores/<store>/model.fga150```151152 If validation fails: read the reported relation or type errors, fix the model, and re-run validation before continuing.1531546. Run the store tests.155 Run:156157```bash158fga model test --tests stores/<store>/store.fga.yaml159```160161 If tests fail: update tuples, assertions, or permission definitions, then re-run tests until all checks and list queries pass.1621637. Only then finalize delivery.164 For touched stores, finish only after validation and tests are green.165 Final rule to check: `workflow-validate`.166167## Full Compiled Document168169For the complete guide with all rules expanded: `AGENTS.md`