- User Groups
- Hierarchies
- Nested Permissions
- Recursive ReBAC
User Groups
Managing access for groups is more efficient than assigning roles to individual users at scale. If a user belongs to a group, they inherit the group’s permissions.Define the base entities
entity user {}
entity organization {
// organizational roles
relation admin @user
relation member @user
}
Model the team entity as a group
A
team has an owner, direct members, and a reference back to the organization it belongs to. Permissions on the team itself use boolean combinations of these relations.entity team {
// represents owner or creator of the team
relation owner @user
// represents direct members of the team
relation member @user
// reference for the organization this team belongs to
relation org @organization
// org admins or team owners can edit and delete
permission edit = org.admin or owner
permission delete = org.admin or owner
// inviting requires being an org admin AND a team owner or member
permission invite = org.admin and (owner or member)
// only team owners can remove users
permission remove_user = owner
}
Attach resources to the group
A
project references both its team and its organization. Permissions are expressed in terms of team membership and org roles.entity project {
relation team @team
relation org @organization
permission view = org.admin or team.member
permission edit = org.admin or team.member
permission delete = team.member
}
Complete Schema
entity user {}
entity organization {
relation admin @user
relation member @user
}
entity team {
relation owner @user
relation member @user
relation org @organization
permission edit = org.admin or owner
permission delete = org.admin or owner
permission invite = org.admin and (owner or member)
permission remove_user = owner
}
entity project {
relation team @team
relation org @organization
permission view = org.admin or team.member
permission edit = org.admin or team.member
permission delete = team.member
}
This model establishes a hierarchy where organizations contain teams, which in turn contain projects. A user’s membership in a team automatically propagates to every project that team owns.
Organizational Hierarchies
Hierarchical permissions allow a user’s access at a higher level of an organization to flow down through every level beneath it. Each lower entity inherits from itsparent.Define top-level roles on the organization
entity user {}
entity organization {
relation admin @user
relation member @user
action view = admin or member
action edit = admin
}
Inherit permissions in the department
The
department entity stores a parent relation pointing to an organization. Its actions delegate to parent.view and parent.edit, so anyone who can act on the organization can also act on the department.entity department {
relation parent @organization
relation manager @user
action view = parent.view or manager
action edit = parent.edit or manager
}
Complete Schema
entity user {}
entity organization {
relation admin @user
relation member @user
action view = admin or member
action edit = admin
}
entity department {
relation parent @organization
relation manager @user
action view = parent.view or manager
action edit = parent.edit or manager
}
entity project {
relation parent @department
relation lead @user
action view = parent.view or lead
action edit = parent.edit or lead
}
admin of an organization can automatically view and edit every department and project beneath it, without any additional relationship tuples.Nested / Inherited Permissions
Thepermission keyword (as opposed to action) is used when a computed permission needs to be inherited by a child entity as a relation. This lets you thread deeply nested relationships through multiple entity levels.Define a permission on an intermediate entity
In the example below,
post exposes a group_member permission that surfaces the group’s membership relation.entity post {
// the group this post belongs to
relation group @group
// surface the group's member set as a permission
// so child entities can reference it
permission group_member = group.member
}
Reference the inherited permission in a child entity
comment belongs to a post. Rather than re-linking to the group directly, it uses post.group_member — a single dot-traversal that resolves the full membership chain.entity comment {
relation owner @user
relation post @post
// a user can view a comment if they own it
// OR if they are a member of the group the post belongs to
action view = owner or post.group_member
}
Complete Schema
entity user {}
entity group {
relation member @user
}
entity post {
relation group @group
permission group_member = group.member
}
entity comment {
relation owner @user
relation post @post
action view = owner or post.group_member
}
The
permission keyword signals that this computed set can be used as a relation target in child entities. Using action would not allow this traversal. This distinction is especially important for multi-level hierarchies.This pattern is common in social platforms where a comment’s visibility is determined by the group or community the parent post belongs to.
Recursive Relationships
Permify Schema supports self-referential (recursive) relations within the same entity. This is useful for modeling parent-child organization trees, folder hierarchies, or any structure with an arbitrary depth.Model a flat parent-child relationship
Here, an
organization can have a parent that is also an organization, and members can view their own organization.entity user {}
entity organization {
relation parent @organization
relation member @user @organization#member
action view = member or parent.member
}
parent.member resolves one level up — members of the direct parent can view the child. This does not traverse multiple levels.Enable multi-level traversal with recursive view
Replace
parent.member with parent.view. Because view itself calls parent.view, the check recurses upward through the entire ancestor chain.entity user {}
entity organization {
relation parent @organization
relation member @user @organization#member
action view = member or parent.view
}
How It Works
Given the following organization hierarchy:Organization Alpha
└── Organization Beta
└── Organization Gamma
organization:beta#parent@organization:alpha
organization:gamma#parent@organization:beta
organization:alpha#member@user:1
Can user:1 view organization:gamma? resolves as:organization:gamma#view→member or parent.viewparent.view→organization:beta#view→member or parent.viewparent.view→organization:alpha#view→member→ ✅user:1is a member
Credits to Léo for highlighting this recursive use case.