Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

LaraMite's avatar

Roles & Multi-Tenant An Open Question...

I posted this on Reddit and thought I might find help for this question here as well

Background (you can skip this part at your own peril):

I've been trying to make a multi-tenant application with roles. It's been going well so far. Multi-tenant set up, check. Basic auth setup with Google OAuth, check. Roles & permissions, can't be that hard, right?

"Roles and permissions can be global or per tenant but they can't be both"

"it has to be teams all the way down"

"What's wrong, there's no use cases that you would need to use both global and tenant-based"

"If you think it can be done then why not create the functionality from scratch"...

The research has not come up with the best answers, to say the least. I understand why permission must be one or the other but there has to be a workaround to accomplish the end goal. Which is, how can you assign a user a global role/permission while still being able to assign them a team/tenant role/permission?

What Are The Use Cases:

  • When you create a new tenant and want to automatically assign users with a particular global role to that tenant.
  • Restricting access to global functions, like creating more tenants. I can imagine a situation where the developer might want a group of people to be able to create new tenants but would never want it to be a possibility for the admin/owner of a team/tenant to be able to create new tenants. "Just make it so the global super-admin can create new tenants", leaving non-critical actions to only the super-admin creates a bottleneck for whoever the super-admin is.
  • Targeting a group for mass action - send emails to all employees saying "X". Sending an email to all employees will send an email to all users that have the role of employee. Both people are internal employees with the employee role and tenant employees with the employee role. Sure there are workaround for this but I would like to limit the possibility of sending sensitive information to the wrong group of people defined by roles.

Possible solutions (I have come up with but I don't think are the best):

  • Use two role/permission packages that won't conflict. One for tenant role assignment, and one for global role assignment.
  • Add is_internal column to the user table. Drawback is I am only checking if a user is part of the base organization and not differentiating between the hierarchy of user roles.
  • Use global role/permission all the way down and append the tenant's name to the role/permission. Example: permission edit_post_tenant_x, check can user ('edit_post_' + current_tenant_name), and global check can user ('edit_post').

Links to articles, blogs, Newspaper clips, or any other resources would be greatly appreciated.

0 likes
2 replies
LaryAI's avatar
Level 58

One possible solution is to use a combination of global and tenant-based roles/permissions, but with a clear hierarchy and rules for how they interact. Here's an example approach:

  1. Define a set of global roles/permissions that apply to all tenants, such as "admin", "employee", "guest", etc. These roles/permissions should be managed at the global level and apply to all tenants.

  2. Define a set of tenant-specific roles/permissions that apply only to a particular tenant, such as "tenant_admin", "tenant_employee", etc. These roles/permissions should be managed at the tenant level and apply only to users within that tenant.

  3. Define a set of rules for how these roles/permissions interact. For example, a user with a global "admin" role should have access to all tenant-specific roles/permissions within their own tenant, but not in other tenants. Similarly, a user with a tenant-specific "tenant_admin" role should have access to all global roles/permissions, but only within their own tenant.

  4. Implement these rules in your application code, using a combination of global and tenant-specific checks to determine a user's access level. For example, you might have a function that checks if a user has a particular role/permission within their own tenant, and another function that checks if they have a global role/permission.

Here's an example implementation in Laravel:

// Define global roles/permissions
Gate::define('admin', function ($user) {
    return $user->isGlobalAdmin();
});

// Define tenant-specific roles/permissions
Gate::define('tenant_admin', function ($user, $tenant) {
    return $user->isTenantAdmin($tenant);
});

// Check if user has a particular role/permission within their own tenant
if (Gate::forUser($user)->allows('tenant_admin', $tenant)) {
    // User has tenant-specific admin access
}

// Check if user has a global role/permission
if (Gate::forUser($user)->allows('admin')) {
    // User has global admin access
}

This approach allows you to have both global and tenant-specific roles/permissions, while still maintaining a clear hierarchy and rules for how they interact. It also allows you to handle use cases such as automatically assigning users to a particular tenant, restricting access to global functions, and targeting a group for mass action.

LaraMite's avatar

I think this is a good approach but what if a user is part of multiple tenants? You would have to add the tenant id to the role to differentiate which role the user has in which tenant. By doing this the tenant_id on the role can't be null because it is now a check to differentiate the same role but belonging to different tenants.

Please or to participate in this conversation.