The complete mapping file syntax for Auth0 Relationship Sync, covering rules, tuple templates, tuple filters, iterators, and the expression language.
Auth0 Relationship Sync uses a mapping file to describe how Auth0 events become FGA tuples. A mapping file is a small, declarative YAML document: it matches incoming Auth0 events against rules, pulls out the fields you care about, and produces FGA tuple writes or deletes. This page is the complete syntax reference for that mapping file.Here’s the basic shape: two rules that add and remove a user from an organization as Auth0 emits membership events.
Every write or delete a mapping engine performs ignores conflicts rather than failing: writes pass OpenFGA’s on_duplicate: "ignore" (skip a tuple that already exists), and deletes pass on_missing: "ignore" (skip a tuple that’s already gone). This applies automatically to every tuple template; there’s nothing to configure in the mapping. It’s what makes it safe for a rule to write or delete the same tuple more than once, whether from a genuinely duplicate event or from reprocessing during reconciliation.See Ignoring duplicate or missing tuples for how these options work at the OpenFGA API level.
Tuple filters power two patterns:Reconcile (read-diff-write): the mapping engine reads tuples matching the filter from FGA, computes the delta against the desired state in tuples, and writes the minimum changes. Use this for update events where the source system sends the full new state but not what specifically changed:
Reconcile re-reads the current tuples on every update event, even when the field didn’t change. If the event carries data.previous_object, you can skip no-op events and avoid the read; see Attributes and metadata for both approaches and their trade-offs.Full delete: set action: delete to remove all tuples matching the filter, without writing replacements:
Auth0 emits organization.member.deleted when a user leaves an organization, or when the organization itself is deleted, but never emits organization.member.role.deleted in either case. Left alone, a user’s role-assignment tuples outlive their membership. Add a rule that filters on the user and organization without pinning a relation, so it catches whatever role tuples exist:
This runs alongside your normal membership-removal rule (the one that deletes the member relation). Omitting relation here means it matches and deletes any relation this user has to this organization, including roles assigned as relations directly on the organization via organization.member.role.assigned.This technique assumes roles are modeled as relations on the organization itself. If your model instead writes role assignments to a separate, tenant-wide role:{id} object, a user+organization filter can’t reach those tuples directly, since a role:{id} object isn’t organization-scoped. See Roles: a user, within an organization membership for a pattern that wires role assignments through an intermediate object instead, so a pair of filters on membership removal revokes every role tied to it without needing to enumerate role IDs.
Auth0 emits only the single group.deleted event when a SCIM group is deleted. There’s no fan-out to a group.member.deleted event per member, so a deleted group’s membership tuples outlive the group. Two filters cover this, since the deleted group can appear on either side of a tuple:
The first filter matches every tuple where the deleted group is the object: its direct user members, any child groups nested inside it, and its connection relation tuple if your model has one. The second filter catches the case the first one misses: if the deleted group was itself nested as a member of some other group, that tuple has the deleted group in the user position (group:{{ variables.group_id }}#member), not the object, so it needs its own filter.Tuple filter fields:
Field
Required
Description
object
yes
At minimum a bare type prefix like "group:", even if the filter is really keyed on user.
user
no
Interpolated string, same as a tuple template’s user.
relation
no
Interpolated string, same as a tuple template’s relation.
action
no
"delete" to remove all matching tuples; omit to reconcile against tuples.
Delete can be set per-tuple (action: delete inside a tuple template); see the “Remove user from organization” example above.Deleting nested/userset members uses the #relation suffix syntax:
when guards and variable expressions use the Expr language. Expressions are sandboxed: no file I/O, network, or shell access.Available context:input (the full input document), variables (values computed earlier in the same rule), and the iterator alias inside iterator rules.String functions:lower(s), upper(s), trim(s), replace(s, old, new), split(s, sep), join(arr, sep), hasPrefix(s, prefix), hasSuffix(s, suffix), contains (infix operator: "hello" contains "ell").Collection functions:len(x), in (membership: "x" in arr), ?? (null-coalescing: value ?? "default").json_path(obj, path): safely traverses nested structures using a dot-separated path. Returns nil for missing paths instead of throwing.
When to use json_pathTwo-level key access like input.data.object.user.user_id throws if the intermediate key (user) is absent. Use json_path whenever the path may not exist across all input types processed by the same mapping file. Optional chaining (input.data.object?.app_metadata?.department_id) is the lighter-weight alternative when you just need a nil-safe read, not a dynamic path.