This file provides guidance to AI coding agents when working with code in this repository.
OpenFGA is a high-performance ReBAC (Relationship-Based Access Control) authorization engine inspired by Google Zanzibar. It evaluates graph-based authorization queries using set operations (union, intersection, exclusion).
Project priorities (in order):
- Correctness — all authorization results must be accurate
- Reliability — the service must be available
- Performance — lowest possible latency and fewest memory allocations
Use make targets, which are the source of truth for builds, tests, and linting.
make build # Build binary to ./dist/openfga
make test # Generate mocks + run all tests with race/coverage
make test FILTER="TestCheckLogs" # Run specific test(s)
make test-bench # Run benchmark tests with -benchmem
make test-docker # Run tests requiring Docker
make lint # golangci-lint v2 with auto-fix
make generate-mocks # Generate mock stubs (also run by `make test`)
make dev-run # Hot-reload dev server (in-memory)
DATASTORE="postgres" make dev-run # Hot-reload with postgres (requires Docker)HTTP/gRPC Request → Middleware → Server Handler → Command → Graph Resolution → Storage → Response
| Directory | Purpose |
|---|---|
cmd/run/run.go |
Server startup, configuration, graceful shutdown |
pkg/server/ |
gRPC/HTTP API handlers |
pkg/server/commands/ |
Business logic layer (decoupled from transport) |
internal/graph/ |
Core authorization check engine (LocalChecker, resolver chain) |
internal/planner/ |
Thompson Sampling strategy planner for resolver selection |
pkg/storage/ |
OpenFGADatastore interface + implementations (memory, postgres, mysql, sqlite) |
pkg/typesystem/ |
Authorization model parsing/validation, weighted_graph.go for query path optimization |
internal/validation/ |
Tuple/request validation against type system |
internal/authn/, internal/authz/ |
Authentication (None, Preshared Key, OIDC) and API authorization |
Resolvers are composed as a circular linked list (last delegates back to first). Resolvers are conditionally added based on configuration:
[CachedCheckResolver]? → [DispatchThrottlingCheckResolver]? → [ShadowResolver | LocalChecker] ⟲
CachedCheckResolver- Added if caching enabledDispatchThrottlingCheckResolver- Added if throttling enabledShadowResolver- Wraps twoLocalCheckerinstances (main + shadow) for A/B testing; added only if shadow mode enabled. Otherwise, a plainLocalCheckeris used.
Construction: internal/graph/builder.go. Interface: internal/graph/interface.go.
Import aliases are enforced by golangci-lint (importas with no-unaliased: true):
openfgav1forgithub.com/openfga/api/proto/openfga/v1parserforgithub.com/openfga/language/pkg/go/transformer
Import order (enforced by gci): standard → external → github.com/openfga → local module
- Interfaces: No "I" prefix (
CheckResolvernotICheckResolver) - Constructors:
New<Type>(), options:With<Property>(), option types:<Type>Option func(*<Type>) - Errors: Sentinel pattern
Err<Name>(e.g.,ErrNotFound), wrap withfmt.Errorf("context: %w", err) - Constants: Exported PascalCase, unexported camelCase, context keys:
<name>CtxKey
- Sentinel errors in
var ()blocks:var ErrNotFound = errors.New("not found") - Always wrap with
%w(never%v), check witherrors.Is/errors.As(never==) - Domain → API error mapping via
<Command>ErrorToServerErrorconverter functions
Follow TDD: write failing test → observe failure → implement → run tests → refactor.
Legacy test format for Check, ListObjects, and ListUsers APIs. Test files embedded via go:embed in assets/assets.go:
assets/tests/consolidated_1_1_tests.yaml- Core relationship testsassets/tests/abac_tests.yaml- Condition/CEL tests
tests:
- name: descriptive_test_name
stages:
- model: |
model
schema 1.1
type user
type document
relations
define viewer: [user]
tuples:
- object: document:1
relation: viewer
user: user:alice
checkAssertions:
- tuple: { object: document:1, relation: viewer, user: user:alice }
expectation: true
listObjectsAssertions:
- request: { user: user:alice, type: document, relation: viewer }
expectation: [document:1]
listUsersAssertions:
- request: { object: document:1, relation: viewer, filters: [user] }
expectation: [user:alice]Runners: tests/check/check.go, tests/listobjects/listobjects.go, tests/listusers/listusers.go (each has RunAllTests()).
Note: The primary tests for OpenFGA server algorithm correctness are the various "Matrix" tests, also located in the tests directory.
internal/mocks/- Auto-generated bymockgen. Runmake generate-mocksto regenerate.*.pb.go- Generated protobuf code.- Protobuf definitions - Live in openfga/api repo. Changes require a PR there first.
- Mock generation:
make testrunsmake generate-mocksautomatically. If usinggo testdirectly, rungo generate ./...first. - Import aliases enforced:
openfgav1andparseraliases are required. Raw import paths fail linting. - Storage integration tests need Docker: Use
make test-dockerfor Postgres/MySQL tests. - Resolver chain is circular: Last resolver delegates back to first. Be aware when debugging
internal/graph/builder.go. - Protobuf changes require separate repo: Update
openfga/apifirst, thengo get github.com/openfga/api@<version>. - golangci-lint is v2: Config file
.golangci.yamlusesversion: "2"format.
- New API endpoint: Define protobuf in
openfga/api→ handler inpkg/server/{method}.go→ command inpkg/server/commands/{method}_command.go→ tests - Storage interface changes: Update
pkg/storage/storage.go→ test inpkg/storage/test/storage.go→ implement for all backends - Graph resolver: Implement
CheckResolverinterface (internal/graph/interface.go) → add builder option ininternal/graph/builder.go→ tests - TypeSystem changes: Update
pkg/typesystem/typesystem.goandweighted_graph.go→ validation tests