---
title: "What Is Relationship-based access control (ReBAC)?"
description: "Learn about Relationship-Based Access Control (ReBAC): how it works, its benefits for flexible authorization, and how Auth0 FGA helps implement it effectively."
authors:
  - name: "Will Johnson"
    url: "https://auth0.com/blog/authors/will-johnson/"
date: "Jun 16, 2025"
category: "Developers,Concepts"
tags: ["fga", "rebac"]
url: "https://auth0.com/blog/relationship-based-access-control-rebac/"
---

# What Is Relationship-based access control (ReBAC)?

You know how on a git repository your permissions feel so intuitive? You're not just a generic 'user' across the whole application. You might be the owner of your own repo, a maintainer with merge rights on a team project, and only have permission to help organize the bug reports and feature requests on an open-source library you contribute to.

This whole system, where your permissions change based on your specific connection to a repo, a pull request, or an organization is the core idea behind Relationship-Based Access Control (ReBAC). It’s an authorization model based on how users work together. Access is defined by your relationship to the resource and not just what role you’re assigned.

ReBAC isn't the only choice for access control. It's one tool in a toolbox that includes other models like [RBAC](https://auth0.com/docs/manage-users/access-control/rbac) and [ABAC](https://auth0.com/blog/what-is-abac-and-how-to-implement-it-rails-api/#What-Is-Attribute-Based-Access-Control--ABAC--). As a developer, you might then ask, 'Which one is the right tool for my job?'"

To help you navigate that choice, we've put together a detailed post on [how to choose the right authorization model for your SaaS application.](https://auth0.com/blog/how-to-choose-the-right-authorization-model-for-your-multi-tenant-saas-application/)

## Understanding How ReBAC Systems Function

A ReBAC system is built on three main concepts that link together, which we'll break down using a git repository as our example.

**1. Subjects in a ReBAC System**

First up, you have the "Subject." This is the person or service that's trying to do something.

*Example:* A developer's account, `user:jane-doe`.

*Example:* An automated service, like `service-account:git-actions`.

**2. Objects: the Resources Controlled by ReBAC**

Next, there's the "Object." This is the resource the Subject wants to interact with or change.

*Example:* A whole repository, like `repo:acme-corp/webapp`.

*Example:* A specific pull request, like `pr:123`.

**3. Relationships: the Core of ReBAC**

Finally, and most importantly, you have the "Relationship." This is the piece that connects a subject to an object. It’s a simple, stored fact that describes their association. This isn't the permission itself, but a label defining the connection.

These relationships come in two main types:

* A **direct relationship** is a simple, stored fact, like a direct assignment.

*Example:* `user:jane-doe` is a maintainer of `repo:acme-corp/webapp`.


* An **indirect relationship** is where the system connects the dots for you. This is often called inherited permission.

*Example:* Dave gets `write_access` to a repo indirectly simply because he's a member of a team that has that access.

## How Does ReBAC Grant Permissions?

So if the relationship isn't the permission, how is a decision actually made? The system uses a separate set of rules that it checks against the facts.

Let's walk through a real git repository scenario:

* **The Ask:** Jane (`user:jane-doe`) tries to merge a pull request into the main branch of the `acme-corp/webapp repo`.

* **The System Checks:** The system doesn't ask, "Is Jane an admin?" Instead, it asks, "How is Jane connected to this specific repo?"

* **It Finds a Fact:** The system sees the stored fact: (`user:jane-doe`, `maintainer`, `repo:acme-corp/webapp`).

* **It Checks the Rulebook:** The repository's rules say something like: "Anyone with the maintainer relationship is allowed to `merge_pull_request`."

* **The Result:** The fact matches the rule, and the merge is allowed.

The power of this model is its flexibility. It means you can tweak your enforcement rules in GitHub (like requiring two reviews before merging) at any time, without having to go back and change the underlying relationship facts for all your developers.

## Challenges of Implementing ReBAC in Your Authorization System

Thinking about using ReBAC? Here's a quick heads-up on the common challenges you might run into.

### Performance Considerations for Scaling ReBAC

To check one permission, a ReBAC system might have to look up several different relationships that connect together. For example, checking if a user can see a file might involve checking their team memberships, which in turn involves checking the team's parent organization, and so on.

This can sometimes lead to slow queries and performance hits. As your application grows, it takes lots of engineering work to keep those lookups from slowing everything down.

### Designing Effective ReBAC Models

What makes ReBAC so great is its flexible, graph-style structure, but that's also what makes it tricky. The complexity isn't in a long list of rules, but in the designing of the relationship model itself.

Figuring out the "right" way to model your permissions (e.g., should a manager automatically inherit the permissions of everyone on their team?) is a big deal to start with. A poorly designed model can be hard to understand and even harder to change later on.

### Ensuring Audibility in Complex ReBAC Models

A side effect of a complex model is that auditing permissions can be tough. Answering a seemingly simple question like, "Why does Jane have access to this document?" can feel like untangling a ball of yarn. You might have to trace a path through five different indirect relationships involving teams and groups, which can make security reviews and debugging a pain.

### Keeping Your Data in Sync

Another roadblock you could run into is the dual-write problem. If your app's source of truth includes who's on what team or who owns what file lives in your main database and your ReBAC system is a separate service with its own database, it will need its own copy of that data to know what's going on.

And that’s how to get into the dual-write problem. When a manager moves someone to a new team, you've got to update that info in two places: your app's database and the authorization system. So, what happens if the write to your database succeeds, but the one to the auth system fails? Now you've got a user whose status is out of sync with their permissions. That can cause confusing bugs or, even worse, a security risk.

> This is a well-known problem in distributed systems If you want to see the different patterns for solving it, check out this blog post on ["Handling the Dual-Write Problem in Distributed Systems".](https://auth0.com/blog/handling-the-dual-write-problem-in-distributed-systems/)

All of these challenges point to the same advice. Using ReBAC successfully means putting in serious thought at the design stage. It trades the ongoing complexity of other systems for a thoughtful investment in your initial model.

## How Auth0 FGA Helps with ReBAC

So how do you actually use these concepts in a real tool? Let's look at [Auth0 FGA](https://a0.to/auth0-fga-content), a managed service for ReBAC. It provides the tools to get hands-on with the concepts we've been talking about and is built on the open-source [OpenFGA](https://a0.to/fga-content) (inspired by Google's Zanzibar).

Let's model our git scenario to show both direct and indirect permissions.

## Defining the ReBAC Authorization Model in Auth0 FGA

First, we define our authorization model in the Auth0 FGA Model Explorer. This is where we'll spell out the concepts we talked about earlier in the blog post. By defining the types of **objects** to be protected and the possible **relations** a **subject** can have with them. For example, a key **relation** in our model is `can_write`, which grants access if a **subject** has either a direct `maintainer` relationship with the **object**, or an indirect one by being a `member` of a `writer` team.

```js
model
  schema 1.1

type user

type team
  relations
    define member: [user]

type repository
  relations
    define maintainer: [user]
    define writer: [team]    
    define can_write: maintainer or member from writer
```

This model sets up our rule:

* A user gets `can_write` permission directly if they are a `maintainer`.
* A user gets `can_write` permission indirectly if they are a `member` of a `team` that is a designated `writer`.

## Creating Relationship Tuples in Auth0 FGA

Remember how we described a relationship as just a simple, stored fact? Now, it's time to actually store some of those facts in our system.

In the world of Auth0 FGA, each one of these "facts" is stored in something called a Tuple. Think of a Tuple as a single line-item that records one specific relationship, it's the raw data that connects a user to an object and solidifies their connection. You can use **Tuple Management** in the Auth0 FGA dashboard to add Tuples

```js
[
  // 1. Anne is a direct maintainer of the "webapp" repo
  {
    "user": "user:anne",
    "relation": "maintainer",
    "object": "repository:webapp"
  },
  // 2. The "developers" team is a writer on the "webapp" repo
  {
    "user": "team:developers",
    "relation": "writer",
    "object": "repository:webapp"
  },
  // 3. Bob is a member of the "developers" team
  {
    "user": "user:bob",
    "relation": "member",
    "object": "team:developers"
  }
]
```

### Verifying Access in Auth0 FGA

Now for the test. We ask the system simple questions, and it uses the model and the facts to give us an answer. In Auth0 FGA, we write assertions for this.

**Check #1 (Direct Relationship)**

* **Question:** Can Anne write in the "webapp" repo?
* **Answer: Yes.** The system checks the `can_write` rule. It sees that `maintainer` is a type of `can_write`, finds the fact that Anne is a `maintainer`, and grants access.

**Check #2 (Indirect Relationship)**

* **Question:** Can Bob write in the "webapp" repo?
* **Answer: Yes.** This is where the power of the model shines. 

The system checks:

1. Is Bob a direct `maintainer`? No.

2. Is Bob a `member` of a `team` that is a `writer` on this repo?

3. It finds the fact that the `team:developers` is a writer on `repository:webapp`.

4. It then checks if `user:bob` is a `member` of `team:developers`. Yes, it finds that fact.

5. The indirect rule (member from writer) is satisfied. Access granted.

Bob never got permission directly, but the system figured it out by traversing the relationship graph. If you want to get your hands dirty and build this yourself, the [Auth0 FGA documentation](https://docs.fga.dev/getting-started) is the best place to start.

You can see what each of these steps look like in Developer Mode of the Auth0 FGA playground.

![](https://images.ctfassets.net/23aumh6u8s0i/CQLIiE44n6iPLE7wP6xeo/1c02f3f14fc626d391a0b8ab8de5ab71/Screenshot_2025-06-13_at_11.57.21_AM.png)

## Final Thoughts on Relationship-Based Access Control

To bring it all together, ReBAC is an approach for modeling permissions that mirrors how your application actually works. Instead of relying on broad, static roles, it focuses on specific relationships: who owns a document, who is a member of a team, or who is assigned to a task. 

It does need more thought upfront to design that relationship model well. But the payoff for that initial work is an authorization system that's ultimately easier to use and change. When your app's features change, you often end up adding new relationships rather than rewriting hard-coded permission logic.

[Auth0 FGA](https://a0.to/auth0-fga-content) is a tool that provides the high-performance infrastructure for this approach, but the essential first step is always the work of designing a solid model that fits your application's needs.