What Is ReBAC? Relationship-Based Access Control + Examples

- Share:





3366 Members
Relationship-based access control (ReBAC) is an authorization model that grants permissions based on how users and resources are connected, for example owner of a folder, member of a team, or caregiver of a patient. Access is derived by following those relationships through a graph, so permissions inherit across hierarchies instead of being assigned to every resource one by one.
ReBAC sits next to Role-Based Access Control (RBAC) and Attribute-Based Access Control (ABAC) as one of the three common fine-grained authorization models. If you're still deciding which one fits your app, start with our RBAC vs ABAC vs ReBAC decision tree. Most real applications end up mixing models over time, so treat them as thinking tools, not religions.
Quick reminder before we start: this is all about authorization, deciding the right people and services have the right access to the right resources. That's a different problem from authentication, which only tells you who someone is.
ReBAC extends RBAC. RBAC grants a role across a whole resource type ("editors can edit documents"). ReBAC also looks at the relationships between users and specific resource instances, which is what lets you write policies for hierarchical structures like folders and files, or organizations, teams, and projects.
The easiest way to picture ReBAC is as a graph. Each node is a user or a resource instance, and each edge is a relationship. An authorization check becomes a question about the graph: is there a path from this user to this resource that grants this permission?
The classic example is a file system such as Google Drive:

This graph shows a folder called "Bob's Files". Inside it are two more folders, "Bob's Docs" and "Bob's Pics", and each of those holds several files. How do we manage Bob's access to all of them without granting access file by file? Three building blocks do the work.
Relationship tuples. A tuple records one relationship between two specific things: a subject, a relation, and an object. In Google's Zanzibar paper, the notation is object#relation@user, so "Alice owns the plans folder" looks like this (illustrative notation):
folder:plans#owner@user:alice
Permit's docs write the same idea as a subject, a relation, and an object, for example folder:bobs_files is parent of file:budget. Different syntax, same concept: tuples are the facts your policy reasons over.
Resource roles. A resource role is a role that only means something on a given resource type, written as Resource#Role. "A user who is the Owner of a folder" is Folder#Owner. On a single instance, it becomes folder:bobs_files#owner.
Role derivation. A derivation grants a role on one instance because of a role on a related instance. In plain English:
A user who holds the Owner role on a folder also gets the Owner role on every file inside that folder.

Put those together and you stop writing policies per instance. In RBAC, you'd have to give Bob a role that grants direct access to each folder and file, or create a role per folder. In ABAC, you'd stamp an "owner" attribute on every file and folder and write a rule that compares it to Bob's ID. With ReBAC, you record that Bob owns "Bob's Files" and that the other folders and files sit inside it. The graph does the rest, including for files that get added next week.
The ReBAC overview in the Permit docs goes deeper on tuples, resource roles, and derivations if you want the reference version.
Definitions only get you so far. Here are five relationship-based access control examples that show up in real products, each with the relationship chain, the resulting permission, and the policy in one line of plain English.
Chain: user:dana is editor of folder:q3-planning, and folder:q3-planning is parent of doc:roadmap.
Result: Dana can edit the roadmap doc, even though nobody shared that doc with her directly.
This is the pattern most people already understand from using Google Drive. The owner of a doc can share it with an editor or a viewer. Sharing a folder grants access to everything inside it. Link sharing inside a company adds one more relation: instead of pointing at a single user, the viewer relation points at a group, such as "every member of org acme". Zanzibar calls this a userset, and it's why one tuple can grant access to thousands of people without thousands of rows.
Policy: An editor of a folder is an editor of every doc in that folder.
Chain: user:lee is admin of org:acme, org:acme is parent of team:platform, and team:platform is parent of project:billing-api.
Result: Lee is an admin of the billing-api project and of every other project under Acme's teams.
This is the B2B SaaS shape. In pure RBAC you'd end up creating roles like "acme-platform-project-admin" for every combination, which is how role explosion starts (we cover what that does to access reviews in least-privilege evidence). With ReBAC, you define one derivation and let the hierarchy carry it. Tenant isolation falls out of the graph too: there's no path from a user in org:acme to a project in org:globex, so the check fails without a special rule.
Policy: An admin of an org is an admin of every project under that org's teams.
Chain: user:bob is caregiver of member:sam, and member:sam is parent of medical_record:sam and health_plan:sam.
Result: Bob can view Sam's medical records and health plan, but not edit them, and not see anyone else's.
Patients own their records. Members of the same patient group (a family, for example) can view each other's profiles. A patient can name a caregiver, and that single relationship grants view access to their health plan and medical records. We walk through this exact model, with screenshots and code, in the implementation section below, and the full demo lives in the Galactic Health Corporation GitHub repo.
Policy: A caregiver of a member can view that member's health plan and medical records.
Chain: user:bob is owner of folder:bobs_files, which is parent of folder:bobs_docs, which is parent of file:cv.pdf.
Result: Bob owns cv.pdf, two levels down, with no direct assignment on the file.
Nested folders are the simplest case of a parent-child hierarchy, and they can go as deep as your product needs. The part people underrate is the reverse question. Security and support teams rarely ask "can Bob open this file?". They ask "who has access to this file, and why?". Because ReBAC stores access as a graph, you can walk it backwards from the file and get every user and every path that reaches it. That's much harder to answer when access is scattered across per-file ACLs or attribute rules.
Policy: An owner of a folder is an owner of every file and subfolder inside it, at any depth.
Chain: user:maya is assigned_rep of account:cust_447, account:cust_447 is parent of ticket:9912, and agent:support-bot is acting on Maya's behalf with a scope of "read tickets".
Result: The agent can read ticket 9912. It can't read tickets for accounts Maya isn't assigned to, and it can't close the ticket, because closing isn't in its scope.
This is where ReBAC earns its keep in agentic systems. The agent's effective access is the intersection of two things: the delegating user's relationships and the agent's own granted scope. Neither alone is enough. A static role on the agent would let it read every ticket in the tenant; the user's access alone would let it do everything Maya can do. We go much deeper on this pattern in ReBAC for AI agents.
Policy: An agent can read a ticket only if the user it acts for is connected to that ticket's account, and reading is within the agent's scope.
Most ReBAC models are built from a handful of relationship types. Here are the ones you'll use most.
A parent-child hierarchy describes resources nested under other resources, the way files sit inside folders.
In ReBAC, this lets you derive roles from the relationship between two resources, like in the Drive example:

The ReBAC policy for this graph:
A user who holds Folder#Owner also gets File#Owner when the Folder instance is the parent of the File instance.
In simpler words: if a file lives inside a folder, and a user owns that folder, they also own the file.
An organization (or group) relationship lets you write policies about groups of users instead of individuals. Take this example:

Bob, Sam, and Linda are all on the HR team. We want all three to be able to edit the legal documents. Instead of giving each of them editor access to each file, we make them members of the HR group and use one policy:
A user who holds HR_Group#Member also gets Legal_Docs#Editor when HR_Group is the parent of Legal_Docs.
Add a new person to HR, or a new document under the group, and the policy still holds. Nothing to update.
Ownership is the most common direct relationship: a user created a resource, so they own it. It's simple, but it's the anchor for most other derivations (owners can share, owners of a folder own its files, and so on). The Permit docs compare ABAC and ReBAC approaches to ownership if you're choosing between an "owner" attribute and an owner relationship.
Delegation is a relationship that lets one principal act with part of another principal's access: a patient naming a caregiver, a manager delegating approvals, or a user delegating a task to an AI agent. The key design choice is that delegation should grant a subset of the delegator's access, never more, and it should be easy to revoke by deleting a single relationship.
| RBAC | ABAC | ReBAC | |
|---|---|---|---|
| Grants access based on | Role assigned to the user (often per tenant) | Attributes of user, resource, action, environment | Relationships between users and resources (owner, member, parent) |
| Best for | Stable job functions, coarse permissions | Context rules: time, location, clearance, data classification | Hierarchies, sharing, multi-tenant org/team/project, delegation |
| Typical example | "Editors can edit articles" | "Doctors can view records in their department during their shift" | "The owner of a folder can edit every file in it" |
| Breaks down when | Role explosion from per-resource or per-tenant roles | Attribute sprawl; hard to answer "who can access X?" | Rules depend on dynamic context (time, quotas) rather than relationships |
| "Who can access X?" | Easy (list role holders) | Hard (evaluate conditions) | Supported via reverse graph queries |
| Data it needs | User-to-role assignments | Fresh attributes at decision time | Relationship tuples kept in sync with the app |
| Deep dive | What is RBAC? | What is ABAC? | This page |
If you're specifically weighing roles against relationships, our RBAC vs ReBAC comparison goes through the tradeoffs side by side. If the real question is "which model should I pick for my app?", the RBAC vs ABAC vs ReBAC decision tree is the faster route. Short version: you rarely pick just one.
Google described its internal authorization system, Zanzibar, in the paper "Zanzibar: Google's Consistent, Global Authorization System", presented at the 2019 USENIX Annual Technical Conference. Zanzibar stores permissions as relationship tuples and answers checks by evaluating them, and the paper describes it serving services such as Drive, YouTube, Calendar, and Photos. That paper is what took ReBAC from an academic idea to something engineers wanted in production.
Zanzibar is a system, not the model itself, but it shaped how most of the industry now implements ReBAC. Open-source projects such as OpenFGA and SpiceDB follow its tuple-based approach, and Permit's ReBAC uses the same tuple convention. For a side-by-side look at two implementations, see ReBAC in practice: Permit.io vs OpenFGA, and for more on the paper itself, What is Google Zanzibar?.
The rest of this section models the healthcare example from above as a demo application and implements it with Permit. You can see the working version of this demo in this GitHub repo.
The first step in any ReBAC implementation, with any tool, is to draw it. Put your resources on a graph as nodes and the relationships between them as edges. The graph tells you which relations, resource roles, and derivations you actually need. Once the model is mapped, we'll add real users and instances.
These are the policies we want to enforce:
Every app user should be able to view all of their own data (health plan, medical records, and profile data).
App users should be able to see the profiles of other members in their patient groups (family members, caregivers, etc.).
Admins should be able to assign users to patient groups.
App users should be able to assign a caregiver role to other members of their patient group, allowing them to view their data (health plan and medical records).
Here are the resources the application needs, and the actions that can be performed on each one:
Member (a user's member profile): View, Edit
Health Plan: View
Medical Records: View
Patient Group: View, Assign, Unassign
In ReBAC, roles aren't only system-wide entities assigned to users (like in RBAC). ReBAC sets up roles per resource, so every resource we just defined gets its own roles:
Member: Owner (can view and edit), Group Member (can view), Caregiver (can view)
Health Plan: Owner (can view and edit), Caregiver (can view)
Medical Records: Owner (can view and edit), Caregiver (can view)
Patient Group: Admin (can view, assign, unassign), Group Member (can view)
To set this up in Permit:
Open the Policy screen and select the Resources tab.
Create the four resources and their actions. Then open each resource's three-dot menu, select Edit, and under ReBAC Options, add its roles in Roles on this resource.

Select the Policy Editor tab and check the boxes that give each resource role its permissions, then save.

Next, define how the resources relate to each other. These relations are what the derivations will be built on.
A member can belong to a patient group
Each member has their own health plan and medical records
To set this up in Permit:
On the Resources tab, open the three-dot menu of the resource you want to relate and select Edit.
Under ReBAC Options, find Relations, click Add Relation, and set up the relationship.

If a user is the owner of a member (the member resource represents a member profile), they get the owner role on that member's medical records and health plan instances.
If a user is the caregiver of a member (they hold a caregiver role on a member instance), they get a caregiver role on the medical records and health plan instances of the same member.
If a user is a member of a patient group (they hold a Group Member role on a patient group instance), they get a Group Member role on the other member instances in the same patient group.
To set this up in Permit:
On the Policy screen, select the Roles tab and open the resource role the user should receive.
In Role Derivation, choose the role that derives it, pick the relation that connects the two resources under When, and save.

The Building ReBAC Policies guide in the docs has the current step-by-step version of this flow, including creating instances and assigning instance roles in the Directory.
Here's how the whole model looks on a graph:

With the model in place, let's apply it to real users.
Let's take the model and apply it to two actual users, Sam and Bob.

First, the direct relationships (in black) and role assignments (in green):
There's one Patient Group instance, with Bob as an Admin and Sam as a Group Member.
There are two Member Profile instances that belong to the same Patient Group. Bob and Sam each have an Owner role assignment on their own Member Profile instance.
Bob is assigned as a Caregiver on Sam's Member Profile instance.
Each Member Profile instance is the parent of two resource instances: Medical Plan and Medical Record.
Now the role derivations:
Sam has a Group Member role on Bob's Member Profile instance, derived from his Group Member role assignment on the Smith Family Patient Group. This lets Sam view Bob's member details.
Sam and Bob each have an Owner role on their own Medical Plan and Medical Records, derived from their Owner role assignment on their Member Profile instances.
Bob has a Caregiver role on Sam's Medical Plan and Medical Records, derived from his Caregiver role on Sam's Member Profile instance.
Using Permit's APIs, with functions such as sync_user and assign_role, you can reproduce this structure in a real application without building the graph engine yourself. Permit's SDKs wrap those API calls for you.
await permit.api.roleAssignments.assign({
user: sam,
role: 'group_member',
resource_instance: `patient_group:bobs_group`,
tenant: 'default',
});
await permit.api.relationshipTuples.create({
subject: `patient_group:bobs_group`,
relation: 'belongs',
object: `member:sam`,
tenant: 'default',
});
An example using Permit's Node.js SDK: assigning Sam the "Group Member" role in Bob's patient group, and creating a relationship tuple between Bob's group and Sam's member profile.
Now that we've covered implementation, here's an honest look at the tradeoffs of choosing ReBAC.
Handles complex hierarchies: ReBAC is designed to represent hierarchies and nested relationships, which makes it the natural fit for folders, org charts, and multi-tenant structures.
Enables reverse queries: The graph structure supports reverse lookups, so you can ask not only "does X have access to Y?" but also "who has access to Y?".
Permissions en masse: Teams, groups, and parent resources let you define access once instead of individually for every single resource.
Avoids RBAC role explosion: Combining relationships with roles is a good way to avoid role explosion, where teams create more and more roles for the sake of granularity until nobody can manage or review them.
Complexity: Building, running, and maintaining ReBAC yourself is real work. You need a model, a tuple store, a graph evaluation engine, and a way to keep all of it consistent.
Graph traversal and data sync cost: A check may have to walk several hops of relationships, and deep or wide hierarchies make that more expensive. The relationship data also has to stay in sync with your application's database, because a stale tuple means a wrong answer.
Harder to audit without the right tooling: Relationship tuples are actually good audit evidence: each one explains exactly why a user could reach a specific resource. The hard part is the broad question, "what can this user access across the whole system?", which needs tooling that can traverse and summarize the graph. We cover this in least-privilege evidence.
Not a replacement for ABAC: ReBAC is great at "who is connected to what", but it isn't built for rules that depend on dynamic context such as time, location, or quotas. Those belong in ABAC-style conditions, which is why most mature systems combine the two.
Least privilege isn't only about enforcement; at some point an auditor or a customer asks you to prove it. ReBAC helps here because every grant traces back to a relationship you can show: "Bob can view this record because he's Sam's caregiver." For how that compares to role assignments and attribute conditions in an access review, read least-privilege evidence.
ReBAC gives people access based on how they're connected to things. If you own a folder, you can open the files inside it. If you're on a team, you can see the team's projects. Instead of assigning permissions to each resource, you record relationships and let access follow them.
Google Drive sharing is the classic one. Share a folder with someone as an editor, and they can edit every doc inside it, including docs added later. Other common examples are org, team, and project hierarchies in SaaS apps, and caregivers who can view a patient's records.
RBAC grants access by role, usually across a whole resource type or tenant. ReBAC grants access through relationships to specific resource instances, like owner of this folder or member of this team. RBAC is simpler; ReBAC handles hierarchies and sharing without role explosion. See our full RBAC vs ReBAC comparison.
No. ReBAC is the authorization model. Zanzibar is Google's system that implements it at massive scale, described in a 2019 USENIX paper. Zanzibar popularized relationship tuples, and open-source projects like OpenFGA and SpiceDB follow its approach.
Yes, and most production systems do. A common pattern is RBAC for broad boundaries, ReBAC for resource-level access through relationships, and ABAC-style conditions for context like time or amount limits. Permit supports mixing all three in one policy.
You can build ReBAC with any of the tools above. In Permit, you define resources, relations, resource roles, and role derivations on the Policy screen, sync relationship tuples from your code with the API or SDKs, and enforce with permit.check(). When a check is allowed or denied, the Audit Log shows why. See Permit's ReBAC page, or go straight to Building ReBAC Policies in the docs.
Want to talk authorization with other developers? Join our Slack community.

Application authorization enthusiast with years of experience as a customer engineer, technical writing, and open-source community advocacy. Comunity Manager, Dev. Convention Extrovert and Meme Enthusiast.