ubxty/multi-tenant-laravel-permissions

A powerful, multi-tenant capable permission handling package for Laravel with role-based access control, wildcard permissions, and high-performance caching.

Installs: 1

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/ubxty/multi-tenant-laravel-permissions

v1.0.0 2026-01-23 09:22 UTC

This package is auto-updated.

Last update: 2026-01-23 09:30:20 UTC


README

Latest Version on Packagist Total Downloads License PHP Version

A powerful, multi-tenant capable permission handling package for Laravel with role-based access control, wildcard permissions, and high-performance caching.

Built by Ubxty

Features

  • 🏢 Multi-Tenancy Support - Tenant-scoped roles and permissions out of the box
  • 🔑 UUID Support - First-class UUID support for roles and permissions
  • High-Performance Caching - In-memory + database JSON caching for minimal DB queries
  • 🃏 Wildcard Permissions - Grant access to permission groups with posts.*
  • 🎛️ Permission Scopes - Attach JSON settings/constraints to permissions per role
  • 🛡️ Middleware - Ready-to-use permission and role middleware
  • 🎨 Blade Directives - Convenient @role, @hasrole, @hasanyrole, @hasallroles, @unlessrole
  • 📦 Laravel 10, 11 & 12 - Full support for modern Laravel versions

Requirements

  • PHP 8.2+
  • Laravel 10.x, 11.x, or 12.x

Installation

Install the package via Composer:

composer require ubxty/multi-tenant-laravel-permissions

Publish the configuration and migrations:

php artisan vendor:publish --provider="Ubxty\MultiTenantLaravelPermissions\MultiTenantPermissionsServiceProvider"

Run the migrations:

php artisan migrate

Setup

1. User Model

Add the HasRoles trait to your User model:

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Ubxty\MultiTenantLaravelPermissions\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;
}

2. Custom Models (Optional)

Extend the package models for custom logic:

// App\Models\Role.php
namespace App\Models;

use Ubxty\MultiTenantLaravelPermissions\Models\Role as BaseRole;

class Role extends BaseRole
{
    // Your custom logic
}

Update your config to use custom models:

// config/multi-tenant-permissions.php
'models' => [
    'permission' => App\Models\Permission::class,
    'role' => App\Models\Role::class,
],

Usage

Creating Roles & Permissions

use App\Models\Role;
use App\Models\Permission;

// Create a Permission
$permission = Permission::create(['name' => 'edit articles']);

// Create a Role (with optional tenant_id for multi-tenancy)
$role = Role::create([
    'name' => 'writer',
    'title' => 'Content Writer',
    'tenant_id' => 1
]);

// Assign Permission to Role
$role->givePermissionTo($permission);

Assigning Roles to Users

$user = User::find(1);

// Assign a role
$user->assignRole('writer');

// Assign multiple roles
$user->assignRole('writer', 'editor');

// Sync roles (replaces current roles)
$user->syncRoles(['writer', 'admin']);

Checking Permissions

// Check if user has a specific permission (direct or via role)
if ($user->hasPermissionTo('edit articles')) {
    // ...
}

// Check if user has a role
if ($user->hasRole('writer')) {
    // ...
}

// Check for any role
if ($user->hasAnyRole(['writer', 'editor'])) {
    // ...
}

Blade Directives

@role('admin')
    <p>Welcome, Admin!</p>
@endrole

@hasanyrole('writer|editor')
    <p>You can write or edit content.</p>
@endhasanyrole

@hasallroles('writer|editor')
    <p>You are both a writer and an editor!</p>
@endhasallroles

@unlessrole('admin')
    <p>You are not an admin.</p>
@endunlessrole

Laravel's native @can directive also works seamlessly:

@can('edit articles')
    <button>Edit Article</button>
@endcan

Multi-Tenancy

This package supports multi-tenancy out of the box. Roles and permissions can be scoped to a specific tenant.

Configuration

// config/multi-tenant-permissions.php
'column_names' => [
    'tenant_column_name' => 'tenant_id', // or 'organization_id', 'team_id', 'workspace_id', etc.
],

Tenant-Scoped Methods

// Check if user has a role for a specific tenant
if ($user->hasRoleForTenant('admin', $tenantId)) {
    // ...
}

// Assign a role for a specific tenant
$user->assignRoleForTenant('manager', $tenantId);

// Get all roles for a specific tenant
$roles = $user->getRolesForTenant($tenantId);

// Sync roles for a specific tenant
$user->syncRolesForTenant(['editor', 'writer'], $tenantId);

// Check if user has a permission for a specific tenant
if ($user->hasPermissionForTenant('edit posts', $tenantId)) {
    // ...
}

High-Performance Caching

This package implements a dual-layer caching system for optimal performance:

  1. Database JSON Cache: Permissions and roles are cached as JSON in columns on the users table
  2. In-Memory Cache: Parsed once per request, all subsequent checks use RAM

Setup

Add cache columns to your users table:

Schema::table('users', function (Blueprint $table) {
    $table->json('permissions_cache')->nullable();
    $table->json('roles_cache')->nullable();
});

Performance Impact

Scenario Without Cache With Cache
Dashboard with 20 permission checks 20+ DB queries 1 DB query
Kanban board with 50 items 50+ DB queries 1 DB query

Wildcard Permissions

Grant access to a group of permissions with wildcards:

// Create specific permissions
Permission::create(['name' => 'posts.create']);
Permission::create(['name' => 'posts.edit']);
Permission::create(['name' => 'posts.delete']);

// Create wildcard permission
$wildcard = Permission::create(['name' => 'posts.*']);

// Assign wildcard - grants access to all posts.* permissions
$user->givePermissionTo($wildcard);

$user->can('posts.create'); // true
$user->can('posts.edit');   // true
$user->can('posts.delete'); // true

Permission Settings & Scopes

Attach JSON settings to permissions when assigning to roles:

$role = Role::findByName('manager');

// Grant permission with specific scope settings
$role->givePermissionToWithSettings('view_projects', [
    'scope' => 'team_only',
    'limit' => 10
]);

// Update settings
$role->updatePermissionSettings('view_projects', [
    'scope' => 'global'
]);

// Retrieve settings
$settings = $role->getPermissionSettings('view_projects');

Middleware

Register Middleware

In Laravel 11+, add to your bootstrap/app.php:

->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'role' => \Ubxty\MultiTenantLaravelPermissions\Middleware\RoleMiddleware::class,
        'permission' => \Ubxty\MultiTenantLaravelPermissions\Middleware\PermissionMiddleware::class,
        'role_or_permission' => \Ubxty\MultiTenantLaravelPermissions\Middleware\RoleOrPermissionMiddleware::class,
    ]);
})

Usage

Route::group(['middleware' => ['role:admin']], function () {
    // Admin only routes
});

Route::group(['middleware' => ['permission:edit posts']], function () {
    // Users with 'edit posts' permission
});

Route::group(['middleware' => ['role_or_permission:admin|edit posts']], function () {
    // Users with admin role OR 'edit posts' permission
});

Commands

Clear the permission cache:

php artisan permission:cache-reset

Configuration

The config file allows customization of:

  • Models: Custom Role and Permission classes
  • Table Names: Custom database table names
  • Column Names: Custom pivot keys, tenant column, cache columns
  • Cache Settings: Expiration time, cache key, cache store

See the published config/multi-tenant-permissions.php for all options.

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security

If you discover any security related issues, please email info@ubxty.com or open an issue on GitHub.

Credits

License

The MIT License (MIT). Please see License File for more information.