Best Practices for Multi-Tenant Authorization
- Share:
Multi-tenant authorization is a model for managing user permissions across multiple accounts, organizations, or groups. With multi-tenancy, each tenant (e.g., an account or organization) operates in an isolated environment, requiring unique access controls tailored to specific user roles within that environment.
One of the most effective ways to implement multi-tenant authorization is by combining it with Role-Based Access Control (RBAC). RBAC simplifies access management by assigning users predefined roles that dictate their permissions within an environment.
RBAC alone faces three major challenges as applications scale and require more fine-grained permissions:
- Being limited to roles (and not attributes and relationships), RBAC may lack granularity.
- Its static roles lack the ability to scale across tenants.
- As applications grow, the number of roles can become unmanageable, resulting in what is called a “Role Explosion.”
A multi-tenant RBAC model solves these issues by structuring user access per tenant, allowing dynamic role assignments and permissions within isolated environments. Instead of assigning a user a single global role, their permissions depend on which tenant they are in and what role they have within that tenant.
Here’s a quick example of when this can be useful:
Think of a SaaS project management platform where users can be members of multiple organizations, each with distinct access levels: A user might be an admin in one organization with full control, while only an editor in another, limited to modifying tasks but not managing users.
Multi-tenant RBAC ensures that permissions are scoped to the right environment without unnecessary complexity.
In this guide, we’ll explore the importance of Multi-Tenant Authorization, and show how it can be efficiently implemented using Permit.io.
We’ll discuss how to structure policies, assign roles per tenant, and enforce fine-grained permissions.
Let’s dive in.
Why is Multi-Tenant Authorization Important?
Multi-tenant authorization is useful for applications where users belong to multiple independent environments, each with its own access rules - a common occurrence in most modern cloud-based applications.
Handling Permissions Across Isolated Environments
With multi-tenancy, each user can receive a tailored approach to their access control based on their tenant. As a user might have different roles and responsibilities across different tenants, the use of multi-tenancy allows those roles must be managed and enforced independently.
This means we can use multi-tenant authorization to maintain clear boundaries between environments while ensuring that users have the appropriate permissions within each one.
For example, consider a cloud storage platform where each customer (tenant) stores sensitive data. It’s crucial to enforce strict access control so that a user from one customer cannot view or modify data from another.
But why can’t we just solve this with RBAC?
Why Traditional RBAC Isn’t Enough for Multi-Tenant Authorization
A lot can be said about the limitations of RBAC. When dealing with applications in production, RBAC can prove too rigid and become too complex to scale. Let’s focus on the aspects multi-tenancy can solve:
Static Roles Don't Scale Across Tenants:
In a traditional RBAC implementation, roles usually apply globally across an application.
This means a user assigned an Editor role might have access to edit all resources, even across tenants where they shouldn’t have permissions.This problem can present itself as simply as:
A project management app where a user is an Editor in one team but should only have Viewer access in another.
Multi-Tenant RBAC allows roles to be scoped per tenant, so a user can be an Editor in one organization and a Viewer in another without unnecessary role duplication. Speaking of role duplication -
The Role Explosion Problem
A basic RBAC model can start simple: Admin, Editor, Viewer. As more users and resource types are introduced, a role explosion can occur. If we take our previous example where a single user needs to be an Editor in one team but a Viewer in another, you can easily end up with something like this:
Editor_TeamA
Editor_TeamB
Viewer_TeamA
Viewer_TeamB
- … and so on for every additional team / potential tenant.
This makes the system hard to manage and difficult to update without breaking access rules.
Multi-Tenant RBAC removes the need for tenant-specific roles by dynamically assigning roles within each tenant instead of hardcoding them.
Multi-Tenant Authorization Requires Granularity
RBAC is often too restricted when handling permissions at a granular level. It typically lacks built-in mechanisms to define resource-level or conditional access policies.
This of this policy:
"Editors can only modify their own photos"
How simple is that? The thing is - there’s no way RBAC can support such a policy without implementing additional logic. Especially at scale.
Before we dive into implementation and best practices, let’s mention a few commonly used multi-tenancy models:
Common Multi-Tenant Models
Multi-tenant authorization applies to a wide range of applications. Here are some of the most common ways tenants are structured:
- Accounts – Used in consumer SaaS applications, where each user belongs to an independent account (e.g., Google Drive, Dropbox).
- Organizations – Common in business applications, where a company (organization) has multiple users with varying roles (e.g., Slack, Notion).
- Groups – Useful for collaborative environments, where users are grouped based on shared access needs (e.g., GitHub teams, project workspaces).
- Franchises – In systems where businesses operate under a franchise model, each franchise functions independently but follows a central structure (e.g., restaurant management systems).
Each of these models benefits from Multi-Tenant authorization to ensure proper isolation and role-based permissions per tenant.
Understanding the benefits of multi-tenant authorization, let’s proceed to discussing implementation.
Best Practices for Implementing Multi-Tenant Authorization
Effective strategies to manage roles, permissions, and scaling across isolated environments in multi-tenant applications.
Plan Your Multi-Tenant Authorization Strategy
Before diving into implementing anything, it’s essential to plan how your multi-tenant model will work. The goal is to ensure that each tenant has separate, manageable access controls for its users. Here are some key elements you should define if you are using an RBAC model:
- Users: Individuals accessing the system. Each can belong to multiple tenants.
- Tenants: Separate environments in which users operate (Like account, organization, or workspace).
- Roles: Predefined permission levels assigned to users within a tenant.
- Resources: Objects (e.g., photos, documents) that users interact with, controlled by permissions.
- Permissions: Rules that define the actions that roles can perform on specific resources.
By addressing these questions early, you can build a flexible and scalable authorization system tailored to your application’s needs.
Understanding Multi-Tenant Scopes
Since a single user can exist in multiple tenants, the system needs to ensure:
- Role assignments are per tenant – A user’s permissions should be scoped to their specific tenant.
- Resources are linked to tenants – Resources should belong to a specific tenant.
- Permissions are evaluated dynamically – When a user makes a request, the system checks both their role in the tenant and the resource’s ownership.
Optimizing Multi-Tenant Authorization: Decoupling Schema from Data
A common challenge in multi-tenant systems is managing how roles and policies are stored and updated. In traditional systems, roles and permissions are often tightly coupled with the application data. This can create complications when permissions need to change, as you might have to update both the role assignment and the application data itself.
To optimize for scalability:
- Decouple policy schema from application data. Store roles, assignments, and policies in a dedicated authorization system (like Permit.io), and keep application data separate from the authorization logic.
- This decoupling allows you to update roles or permissions dynamically without touching the application’s core data or codebase.
Permit.io’s no-code policy management UI allows you to make policy changes without ever touching the codebase.
This is also true for handling role assignments for multiple tenants.
Use One Source of Truth - The PDP (Policy Decision Point)
One of the critical concepts in optimizing multi-tenant authorization is using a single source of truth to make policy decisions.
Instead of storing role information and access rules within each service or user database, the Policy Decision Point (PDP) acts as the central point where all access decisions are made.
Benefits of using a PDP:
- Consistency: The PDP ensures that all services across the application reference the same set of rules when making authorization decisions.
- Dynamic Policy Evaluation: Changes to policies or role assignments only need to be updated in one location—the PDP. This centralization removes the need for updating multiple places in your codebase or databases.
- Less Risk of Error: By relying on a single, centralized decision point, you reduce the risk of inconsistent permissions across tenants and applications.
Extending RBAC with Relationship-Based Access Control (ReBAC)
While RBAC provides a solid foundation for multi-tenant authorization, there are scenarios where relationship-based access control (ReBAC) can offer even more fine-grained access control.
RBAC defines permissions based on roles assigned to users, but ReBAC takes it a step further by defining permissions based on the relationships between resources and users. This is especially useful in situations where permissions depend on how resources are connected or associated with each other.
For example, Imagine a document management system where a user has access to a folder
, and that folder contains multiple documents. With RBAC, you would need to define roles like Folder Editor
or Document Viewer
. However, with ReBAC, you could simplify this by saying:
“A user is allowed to edit a document if they are an editor of the folder that the document belongs to.”
This allows more dynamic and context-sensitive permission assignments without duplicating roles for every resource.
Role derivation allows for the dynamic assignment or inheritance of roles based on certain conditions or relationships. This allows roles to be contextually derived based on a user's relation to a resource, for example.
Benefits of ReBAC:
- Contextual Permissions: Allows access control based on dynamic relationships (e.g., a user being an editor in a project, and therefore having access to all related tasks).
- Reduced Role Explosion: You don’t need to create roles for every combination of user and resource type, as relationships can define access dynamically.
By extending RBAC with ReBAC, you can handle complex access control scenarios where relationships between users and resources dictate permissions.
Implementing Multi-Tenant Authorization with Permit.io
Permit.io offers a simple way to implement multi-tenant authorization by allowing you to define roles, policies, and access rules across different environments.
if (user.role == admin && user.tenant == resource.tenant) {
return true;
}
A traditional, static if
statement approach for multi-tenancy.
const permitted = await permit.check(user, "read", {
resource: "document",
tenant: "default"
});
if (permitted) {
return true;
}
A clean permit.check()
function that checks for multi-tenancy RBAC.
Here's a broad overview of how multi-tenant RBAC authorization can be set up in Permit.io:
Define Roles, Resources, and Actions:
To get started, first define your resources (e.g., documents, photos, tasks) and the actions that can be performed on them (e.g., create, read, update, delete).- Add a new resource (e.g.,
blog
) to represent the type of object you want to control access to. - Specify the resource's key, which will be used in your API calls.
- Define the actions users should be able to perform on the resource (e.g., create, read, update, delete).
- The screenshot shows an example where
blog
is the resource, and actions are defined for it.
Define the Access Control Policy:
You’ll specify what actions each role can perform on each resource. For example, in the screenshot, roles like admin, public, and Writer are defined, and the policy is set up to specify which actions are permitted for each role.
Define the Tenants in the Directory:
Each tenant can have its own set of roles, permissions, and policies.To create tenants:
- Go to the Directory screen and click on Settings.
- Define the tenants you need (e.g., Tenant 1, Tenant 2, etc.).
- The screenshot illustrates how different tenants are created and managed in Permit.io.
Create Users and Assign Roles:
Once the tenants are defined, you can create users and assign them roles specific to each tenant. This ensures that the same user can have different roles in each tenant, depending on what permissions they need.
To create a new user:
- Click Add User in the Directory screen.
- Assign the user a unique key and other user details (e.g., email, first name).
- In the Permissions Per Tenant section, you can assign the user roles specific to the tenant they belong to. For instance, the user could be an Admin in Tenant 1 and a Writer in Tenant 2, as shown in the screenshot:
Here, we can see all of our users and what roles they have in each tenant they belong to:
Some of the benefits of using Permit.io for multi-tenant authorization include:
- Centralized Policy Management: Define and manage all your authorization rules and policies from a centralized platform. This simplifies policy changes and ensures consistent enforcement across your tenants.
- Tenant-Specific Role Assignment: Easily assign and manage roles per tenant, allowing users to have different roles in different environments (e.g., Admin in one tenant, Viewer in another).
- Fine-Grained Permissions: Implement detailed permissions for each resource and enforce complex fine grained permissions (Like those based on attributes or relationships) without the need for additional custom logic.
- ReBAC Support: Permit.io extends the traditional RBAC model with ReBAC, allowing you to define permissions based not only on user roles but also on the relationships between users and resources. This is especially useful when you need contextual permissions, such as allowing access to resources depending on their organizational structure or hierarchies.
Summing Up: Multi-Tenant Authorization with RBAC
In this blog, we’ve explored the importance of multi-tenant authorization and how combining it with Role-Based Access Control (RBAC) enables more efficient and scalable user permission management across isolated environments.
We’ve discussed the challenges of traditional RBAC in multi-tenant applications and how Multi-Tenant RBAC solves issues such as static roles, role explosion, and fine-grained access control.
With multi-tenant authorization, each tenant can have its own isolated access control, ensuring that users only have access to what they are authorized for within their specific environments.
Permit.io allows you to implement multi-tenant authorization in a more streamlined way, thanks to centralized policy management, tenant-specific role assignment, fine-grained permissions, and support for Relationship-Based Access Control (ReBAC).
What’s Next?
- Explore Permit.io’s documentation to start implementing multi-tenant authorization in your application.
- Join the Permit.io community to discuss best practices and get support.
Written by
Daniel Bass
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.