Skip to main content
Relationship-Based Access Control (ReBAC) is the right choice when access decisions depend on how entities relate to each other rather than on a user’s static role. Classic examples include resource ownership (“the user who created this document can edit it”), group membership (“members of this team can view projects the team owns”), and hierarchy propagation (“organization admins can manage everything under that organization”). Permify was designed as a true ReBAC system, inspired by Google Zanzibar. Relations between entities are first-class concepts in the schema DSL, and permissions can traverse those relations as deeply as your data model requires.

When to use ReBAC

  • Access depends on a user’s relationship to a specific resource (ownership, membership, parentage).
  • Permissions should propagate through entity hierarchies — for example, org admin → team → project.
  • You need to grant a group of users access to a resource by connecting the group entity to the resource.
  • Your permission rules require following a chain of relations across multiple entity types.
ReBAC and RBAC compose naturally in Permify. The three use cases below show progressively more complex patterns, from simple org-scoped roles up to deeply nested hierarchies.

Use case 1: Organization-scoped repository permissions

This example models GitHub-style repository access. Repositories belong to an organization, and the permissions a user has on a repository depend on their role in the parent organization as well as their direct ownership of the repository.

Schema

entity user {}

entity organization {

    // organizational roles
    relation admin  @user
    relation member @user

}

entity repository {

    // parent organization of this repository
    relation parent @organization

    // direct owner of this repository
    relation owner  @user

    // permissions
    action push   = owner
    action read   = owner and (parent.admin or parent.member)
    action delete = parent.admin or owner

}

How permissions propagate

The parent relation on repository points to an organization. Using dot notation (parent.admin, parent.member), permission expressions on repository can reach through to the relations defined on organization.
  • action push = owner — only the direct owner can push.
  • action read = owner and (parent.admin or parent.member) — the owner can read, but only if they are also an admin or member of the parent organization. Users who own the repository but have been removed from the organization cannot read it.
  • action delete = parent.admin or owner — organization admins and the direct owner can delete.

Sample relationship tuples

organization:1#admin@user:daniel
organization:1#member@user:ege
organization:1#member@user:jack

repository:1#parent@organization:1
repository:1#owner@user:ege
Given these tuples: Can user:ege read repository:1?Allow, because ege is the owner of repository:1 and also a member of the parent organization (organization:1). Can user:daniel push to repository:1?Deny, because daniel is not the owner of repository:1, regardless of their admin role.

Use case 2: Deeply nested hierarchies

This example shows how permissions propagate through multiple levels of entity nesting. An organization contains teams, and teams contain projects. Admin rights granted at the organization level flow down through teams to projects automatically.

Schema

entity user {}

entity organization {

    relation admin @user
}

entity team {

    // the organization this team belongs to
    relation org @organization

    // only the organization administrator can edit a team
    action edit = org.admin
}

entity project {

    // the team this project belongs to
    relation team @team

    // team.edit refers to the edit action on the team entity
    // organization admins who can edit the team can also edit the project
    action edit = team.edit
}

How nested permission inheritance works

The key is action edit = team.edit on the project entity. Rather than pointing to a relation, this expression points to an action on a related entity. Permify recursively evaluates team.edit, which in turn evaluates org.admin. The chain is: project.editteam.editorg.admin.

Sample relationship tuples

organization:1#admin@user:1
team:1#org@organization:1
project:1#team@team:1
Can user:1 edit project:1?Allow, because user:1 is an admin of organization:1, which is the parent organization of team:1, which is the parent team of project:1.
You can reference actions on related entities (e.g., team.edit) but not their attributes directly (e.g., team.budget). For attribute-based checks across hierarchies, see Building ABAC Systems.

Use case 3: User groups and team permissions

This example shows how to model a project management application where permissions are determined by team membership and organizational roles. Members of a team inherit the team’s permissions on any project that team owns.

Schema

entity user {}

entity organization {

    relation admin  @user
    relation member @user

}

entity team {

    relation owner  @user
    relation member @user
    relation org    @organization

    // organization admins or team owners can edit and delete
    action edit        = org.admin or owner
    action delete      = org.admin or owner

    // inviting requires org admin AND being an owner or member of the team
    action invite      = org.admin and (owner or member)

    // only the team owner can remove users
    action remove_user = owner

}

entity project {

    relation team @team
    relation org  @organization

    action view   = org.admin or team.member
    action edit   = org.admin or team.member
    action delete = team.member

}

How group-based permissions work

action view = org.admin or team.member on project means: grant view access to anyone who is an admin of the parent organization or a member of the team that owns the project. The org.member relation on team can also be set to a subject set — for example, organization:1#member@team:2#member — meaning all members of team:2 are also treated as members of organization:1. This lets you compose groups without duplicating individual user assignments.

Sample relationship tuples

team:1#owner@user:daniel
team:1#member@user:ashley
organization:1#admin@user:jack
organization:1#member@team:1#member
project:1#team@team:1
Can user:ashley view project:1?Allow, because ashley is a member of team:1, which the project belongs to. Can user:jack delete project:1?Deny, because delete requires team.member and jack is an org admin, not a team member.

Writing relationship data

Relationship tuples are written to Permify with the Data Write API:
cURL
curl --location --request POST 'localhost:3476/v1/tenants/t1/relationships/write' \
--header 'Content-Type: application/json' \
--data-raw '{
  "metadata": {
    "schema_version": ""
  },
  "tuples": [
    {
      "entity": { "type": "repository", "id": "1" },
      "relation": "parent",
      "subject": { "type": "organization", "id": "1" }
    },
    {
      "entity": { "type": "repository", "id": "1" },
      "relation": "owner",
      "subject": { "type": "user", "id": "ege" }
    }
  ]
}'

Checking permissions

cURL
curl --location --request POST 'localhost:3476/v1/tenants/t1/permissions/check' \
--header 'Content-Type: application/json' \
--data-raw '{
  "metadata": {
    "snap_token": "",
    "schema_version": "",
    "depth": 20
  },
  "entity": { "type": "repository", "id": "1" },
  "permission": "read",
  "subject": { "type": "user", "id": "ege" }
}'
Response
{
  "can": "RESULT_ALLOWED"
}

Building RBAC Systems

Model static role assignments — the simplest starting point for access control.

Building ABAC Systems

Add dynamic attribute checks on top of relationship-based rules.

Modeling guide

Full reference for entities, relations, actions, and rules in the Permify Schema DSL.

Sync data

Learn how to write and manage relationship tuples.

Build docs developers (and LLMs) love