Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Permission Laravel Package

spatie/laravel-permission

Manage roles and permissions in Laravel using database-backed models integrated with Laravel’s Gate. Assign roles to users, grant permissions directly or via roles, and authorize actions with the familiar can() checks. Includes docs for setup and usage.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/laravel-permission
    php artisan migrate
    

    Run migrations to create roles, permissions, and model_has_permissions tables.

  2. Add Trait to User Model:

    use Spatie\Permission\Traits\HasRoles;
    
    class User extends Authenticatable
    {
        use HasRoles;
        // ...
    }
    
  3. First Use Case: Create a role and assign it to a user:

    $role = Role::create(['name' => 'admin']);
    $user->assignRole($role);
    

    Check permissions in Blade:

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

Implementation Patterns

Core Workflows

  1. Role-Based Access Control (RBAC):

    // Assign role to user
    $user->assignRole('editor');
    
    // Check role in controller
    if ($user->hasRole('editor')) {
        return view('editor.dashboard');
    }
    
  2. Permission-Based Access:

    // Grant permission directly
    $user->givePermissionTo('publish posts');
    
    // Check permission in middleware
    if (!$user->can('publish posts')) {
        abort(403);
    }
    
  3. Combined Role + Permission:

    // Sync permissions to role
    $role = Role::findByName('admin');
    $role->syncPermissions(['create users', 'delete posts']);
    
    // Assign role to user
    $user->assignRole($role);
    

Integration Tips

  1. Policy Integration:

    use Spatie\Permission\PermissionRegistrar;
    
    public function boot()
    {
        $this->registerPolicies();
        $this->registerPermissions();
    }
    
    protected function registerPermissions()
    {
        app(PermissionRegistrar::class)->for('user', [
            'edit profile',
            'delete account',
        ]);
    }
    
  2. Scopes for Querying:

    // Get users with 'admin' role
    $admins = User::role('admin')->get();
    
    // Get users without 'view posts' permission
    $nonViewers = User::withoutPermission('view posts')->get();
    
  3. Artisan for Seed Data:

    php artisan permission:create-role admin
    php artisan permission:create-permission "manage users" --guard=web
    
  4. Enum Support (Laravel 8+):

    enum PostPermission: string
    {
        case CREATE = 'create posts';
        case EDIT = 'edit posts';
    }
    
    // Usage
    $user->givePermissionTo(PostPermission::EDIT);
    @can(PostPermission::CREATE)
    

Gotchas and Tips

Pitfalls

  1. Guard Mismatch:

    • If using multiple guards (e.g., web, api), ensure permissions/roles are created with the correct guard:
      php artisan permission:create-role admin api
      
    • Fix: Explicitly set guard_name when creating roles/permissions:
      $role = Role::create(['name' => 'admin', 'guard_name' => 'api']);
      
  2. Caching Issues:

    • The package auto-resets cache after changes, but manual cache clearing may be needed if using custom logic:
      php artisan permission:cache-reset
      
    • Tip: Avoid manual cache clearing unless necessary—use the package’s API methods.
  3. Enum Limitations:

    • Enums cannot be used directly in $casts for Permission models (as of v6/v7).
    • Workaround: Use enum_value() helper:
      $permission = Permission::create(['name' => enum_value(PostPermission::CREATE)]);
      
  4. Mass Assignment Risks:

    • Avoid mass-assigning guard_name or name to Role/Permission models directly. Use the package’s methods:
      // ❌ Avoid:
      Role::create(['name' => 'admin', 'guard_name' => 'api']); // May bypass validation
      
      // ✅ Use:
      $role = Role::create(['name' => 'admin']);
      $role->guard_name = 'api';
      $role->save();
      

Debugging Tips

  1. Check Guard Names:

    • Verify guard names match across models, policies, and middleware:
      $user->getGuardName(); // Should match your auth guard
      
  2. Permission Hierarchy:

    • Use getAllPermissions() to debug inherited permissions:
      dd($user->getAllPermissions()->pluck('name'));
      
  3. Artisan Inspection:

    • List all roles/permissions for a guard:
      php artisan permission:show web
      
  4. Middleware Debugging:

    • Add logging to middleware to verify permission checks:
      public function handle(Request $request, Closure $next)
      {
          Log::debug('Checking permission: ' . $request->user()->getPermissionNames());
          return $next($request);
      }
      

Extension Points

  1. Custom Permission Models:

    • Extend Spatie\Permission\Models\Permission to add fields (e.g., description):
      class CustomPermission extends Permission
      {
          protected $casts = [
              'description' => 'text',
          ];
      }
      
    • Update config/permission.php to use your model:
      'models' => [
          'permission' => \App\Models\CustomPermission::class,
      ],
      
  2. Dynamic Permissions:

    • Generate permissions dynamically (e.g., for resources):
      use Spatie\Permission\PermissionRegistrar;
      
      $registrar = app(PermissionRegistrar::class);
      $registrar->for('post', [
          'create',
          'read',
          'update',
          'delete',
      ]);
      
  3. Team Support:

    • Enable teams in config/permission.php:
      'enable_team_roles' => true,
      
    • Assign roles to teams:
      $team->assignRole('team-admin');
      
  4. Policy Integration:

    • Combine with Laravel policies for granular control:
      class PostPolicy
      {
          public function update(User $user, Post $post)
          {
              return $user->can('edit posts') && $user->id === $post->user_id;
          }
      }
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport