> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fga.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Authorization Model Design Principles

> Best practices for creating clear, performant, and maintainable authorization models.

A well-designed authorization model is easier to understand, debug, and maintain. It also performs better and scales more gracefully as your application grows. This guide covers key principles for modeling authorization in Auth0 FGA.

## Core Principle: Model Your Domain, Not a Meta-Model

The most common mistake when starting with Auth0 FGA is creating an overly generic model that can represent "anything." While this seems flexible, it trades clarity for abstraction and often hurts performance.

> [!TIP]
>
> **Rule of Thumb**
>
> **If end-users can define it, store it in tuples. If it's built into your application, define it in the model.**
>
> For example: built-in roles like "admin" or "billing\_manager" should be relations in your model. User-defined custom roles should be stored as tuples with a `role` type.

### The Recommended Approach

Define types and relations that mirror your application's domain. If your app has organizations, projects, and documents, model exactly that with explicit relationships:

FGA model · DSL

Notice how this model has a clear hierarchy (organization → project → document) where each type and relationship directly reflects the application's domain. Permission inheritance follows a well-defined path that's easy to understand and audit.

This approach has several advantages:

* **Enhanced clarity and maintainability**: Authorization logic is easier to understand, debug, and maintain. Developers and security auditors can readily grasp the meaning of each type and relationship just by reading the model.

* **Better performance**: Models with specific types and flatter hierarchies perform better. Auth0 FGA processes queries more efficiently with well-defined types compared to navigating complex recursive relationships within generic types.

* **Easier evolution**: Auth0 FGA's modeling language is designed to be adaptable. You can define numerous distinct types and relationships without significant overhead. Model changes rarely require data migrations, allowing you to evolve your model as your application grows.

* **Team autonomy with modules**: Resource types owned by each application team can be maintained in independent [modules](https://docs.fga.dev/modeling/modular-models.md). You can control which application can write to specific resource types through API credentials, providing better security boundaries.

<details>
  <summary>What to avoid: The overly generic model</summary>

  The model below can technically represent any organization hierarchy, any resource hierarchy, and any role hierarchy:

  FGA model · DSL

  While flexible, this approach creates problems:

  * The model doesn't communicate what your application actually does
  * To understand the actual relationships you need to rely on tuples, e.g., the fact that a project can have documents.
  * Generic recursive relations are slower to evaluate
  * You can't use modules to isolate different resource types
  * ListObjects returns mixed results (all "resources" instead of just "documents")
</details>

## Modeling Roles

Most applications have roles. The key question is: are they built-in or user-defined?

### Built-in Roles

For roles that come with your application (admin, member, viewer, etc.), define them directly as relations:

FGA model · DSL

Adding new built-in roles is straightforward: add a relation to the model. This happens infrequently and doesn't require data migration.

### Custom Roles (User-Defined)

Some applications let end-users create their own roles. In this case, combine static roles with a dynamic `role` type:

FGA model · DSL

This hybrid approach gives you the clarity of static roles for common cases while supporting custom roles when needed.

For more details, see [Modeling Roles](https://docs.fga.dev/best-practices/modeling-roles.md) and [Custom Roles](https://docs.fga.dev/modeling/basics/custom-roles.md).

## Modeling Organizational Structures

B2B SaaS applications often have two distinct organizational requirements:

1. **Super-admin access**: Your company's employees need to access customer data for support or disaster recovery
2. **Customer hierarchies**: Your customers have their own organizational structures

### Super-Admin Access

For internal support and admin access, use a dedicated `system` type rather than making organizations recursive:

FGA model · DSL

This approach:

* Clearly separates your internal access from customer access
* Avoids recursive relations (faster to evaluate)
* Makes audit and compliance reviews easier

See a complete [super-admin example](https://github.com/openfga/sample-stores/blob/main/stores/superadmin) for more details.

### Customer Organization Hierarchies

If customers need hierarchical organizations, prefer explicit types for each level when the structure is well-defined:

FGA model · DSL

This makes the hierarchy explicit: organizations contain departments, and department members inherit from the organization.

If the hierarchy depth is truly dynamic (customers can nest arbitrarily), then add recursion only where needed:

FGA model · DSL

Now you have two distinct hierarchies:

* **System hierarchy**: Non-recursive, for your internal super-admin access
* **Organization hierarchy**: Recursive only if customers truly need arbitrary nesting

Prefer explicit types when possible; use recursion only when the depth is genuinely unbounded.

## Modeling Resource Types

Applications have different kinds of resources: documents, folders, projects, tickets, accounts, etc. Some have parent-child relationships (folders contain documents, projects contain tickets).

### Use Specific Types, Not a Generic "Resource"

Define a type for each kind of resource in your application:

FGA model · DSL

Benefits of specific types:

* **Accurate ListObjects results**: Querying for documents returns only documents, not all resources
* **Type-specific permissions**: `can_print` makes sense for documents but not folders
* **Clearer model**: Each type shows exactly what permissions apply to it
* **Module support**: Different teams can own different resource types

<details>
  <summary>What to avoid: The generic resource type</summary>

  FGA model · DSL

  Problems with this approach:

  * ListObjects returns mixed results (folders, documents, and everything else)
  * You end up with a superset of all permissions, making it unclear which apply to what
  * No way to use modules for team ownership
  * Harder to understand and audit
</details>

## Quick Reference

| Scenario | Recommendation |
| - | - |
| Built-in roles (admin, member) | Define as relations directly in the model |
| User-defined custom roles | Create a `role` type, store assignments as tuples |
| Internal super-admin access | Use a non-recursive `system` type |
| Customer org hierarchies | Add recursive `parent` relation only if needed |
| Different resource types | Create specific types (`document`, `folder`), not generic `resource` |
| Type-specific permissions | Define permissions on the relevant type only |
| Team ownership of resource types | Use modules to separate concerns |

## Related Sections

Check out these related resources for more information about modeling

[Custom Roles
Learn how to implement user-defined custom roles.](https://docs.fga.dev/modeling/basics/custom-roles.md)

[Modular Authorization Models
Learn how to break down your authorization model into modules.](https://docs.fga.dev/modeling/modular-models.md)

[Modeling Roles
Detailed guidance on role-based access control patterns.](https://docs.fga.dev/best-practices/modeling-roles.md)

[Building Blocks
Understand the fundamental concepts for building authorization models.](https://docs.fga.dev/modeling/building-blocks)
