A Go module for mapping JSON events into OpenFGA relationship tuples using a declarative YAML mapping language.
OpenFGA is an open source Fine-Grained Authorization solution inspired by Google's Zanzibar paper. It was created by the FGA team at Auth0 based on Auth0 Fine-Grained Authorization (FGA), available under a permissive license (Apache-2) and welcomes community contributions.
This module turns JSON events into OpenFGA relationship tuples. A mapping is authored in a declarative YAML language, compiled once, and then evaluated against events. The engine is stateless — it produces tuples (and tuple filter operations for read-diff-write flows); it makes no OpenFGA API calls, leaving I/O to the consumer.
It is made up of two packages:
mapper(module root) — compiles validated mapping configurations into an executableMappingand evaluates events against it.language— parses and validates mapping YAML into a canonicalMappingConfig.mapperdepends onlanguage, never the reverse.
- OpenFGA Documentation
- OpenFGA API Documentation
- OpenFGA Community
- Zanzibar Academy
- Google's Zanzibar Paper (2019)
go get github.com/openfga/mapperCompile a mapping and evaluate an event against it:
package main
import (
"context"
"fmt"
"github.com/openfga/mapper"
)
func main() {
yaml := []byte(`
version: "1"
rules:
- name: "grant membership on user creation"
when: input.type == "user.created"
tuples:
- user: "user:{{ input.data.email }}"
relation: "member"
object: "org:{{ input.data.org_id }}"
`)
m, err := mapper.Compile(yaml)
if err != nil {
panic(err)
}
result, err := m.Evaluate(context.Background(), map[string]any{
"type": "user.created",
"data": map[string]any{
"email": "alice@example.com",
"org_id": "acme",
},
})
if err != nil {
panic(err)
}
for _, t := range result.Tuples {
fmt.Printf("%s %s %s\n", t.User, t.Relation, t.Object)
}
}Compile is a one-shot convenience. To compile many sources with the same configuration, build a Compiler once with mapper.NewCompiler(opts...) and reuse it.
When processing a batch of events, call Evaluate per event and accumulate the results. Before writing to OpenFGA, pass the combined tuple slice to Compact to deduplicate and detect conflicts:
var tuples []mapper.Tuple
for _, event := range events {
result, err := m.Evaluate(ctx, event)
if err != nil {
panic(err)
}
tuples = append(tuples, result.Tuples...)
}
compacted, err := mapper.Compact(tuples)
if err != nil {
// err is a *mapper.ConflictError — two incompatible desired states on the same relationship.
panic(err)
}
// compacted is ready to write to OpenFGA.Compact applies the same dedup and conflict-detection semantics Evaluate runs per-record: exact-identity duplicates collapse to the first occurrence, repeated deletes on the same (user, relation, object) collapse, and incompatible desired states (write + delete, or two writes with differing condition/context on the same relationship) are reported as a *ConflictError.
- Language specification — the canonical, user-facing mapping language spec.
- Tuple write specification — how a consumer turns the engine result into OpenFGA API calls.
- Engine architecture — internal design of the
mapperpackage. - Language package — internal design of the
languagepackage.
See CONTRIBUTING.md.
This project is licensed under the Apache-2.0 license. See the LICENSE file for more info.