laravel-permission-development

Laravel Permission Development

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "laravel-permission-development" with this command: npx skills add spatie/laravel-permission/spatie-laravel-permission-laravel-permission-development

Laravel Permission Development

When to use this skill

Use this skill when working with authorization, roles, permissions, access control, middleware guards, or Blade permission directives using spatie/laravel-permission.

Core Concepts

  • Users have Roles, Roles have Permissions, Apps check Permissions (not Roles).

  • Direct permissions on users are an anti-pattern; assign permissions to roles instead.

  • Use $user->can('permission-name') for all authorization checks (supports Super Admin via Gate).

  • The HasRoles trait (which includes HasPermissions ) is added to User models.

Setup

Add the HasRoles trait to your User model:

use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable { use HasRoles; }

Creating Roles and Permissions

use Spatie\Permission\Models\Role; use Spatie\Permission\Models\Permission;

$role = Role::create(['name' => 'writer']); $permission = Permission::create(['name' => 'edit articles']);

// findOrCreate is idempotent (safe for seeders) $role = Role::findOrCreate('writer', 'web'); $permission = Permission::findOrCreate('edit articles', 'web');

Assigning Roles and Permissions

// Assign roles to users $user->assignRole('writer'); $user->assignRole('writer', 'admin'); $user->assignRole(['writer', 'admin']); $user->syncRoles(['writer', 'admin']); // replaces all $user->removeRole('writer');

// Assign permissions to roles (preferred) $role->givePermissionTo('edit articles'); $role->givePermissionTo(['edit articles', 'delete articles']); $role->syncPermissions(['edit articles', 'delete articles']); $role->revokePermissionTo('edit articles');

// Reverse assignment $permission->assignRole('writer'); $permission->syncRoles(['writer', 'editor']); $permission->removeRole('writer');

Checking Roles and Permissions

// Permission checks (preferred - supports Super Admin via Gate) $user->can('edit articles'); $user->canAny(['edit articles', 'delete articles']);

// Direct package methods (bypass Gate, no Super Admin support) $user->hasPermissionTo('edit articles'); $user->hasAnyPermission(['edit articles', 'publish articles']); $user->hasAllPermissions(['edit articles', 'publish articles']); $user->hasDirectPermission('edit articles');

// Role checks $user->hasRole('writer'); $user->hasAnyRole(['writer', 'editor']); $user->hasAllRoles(['writer', 'editor']); $user->hasExactRoles(['writer', 'editor']);

// Get assigned roles and permissions $user->getRoleNames(); // Collection of role name strings $user->getPermissionNames(); // Collection of permission name strings $user->getDirectPermissions(); // Direct permissions only $user->getPermissionsViaRoles(); // Inherited via roles $user->getAllPermissions(); // Both direct and inherited

Query Scopes

$users = User::role('writer')->get(); $users = User::withoutRole('writer')->get(); $users = User::permission('edit articles')->get(); $users = User::withoutPermission('edit articles')->get();

Middleware

Register middleware aliases in bootstrap/app.php :

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

Use in routes (pipe | for OR logic):

Route::middleware(['permission:edit articles'])->group(function () { ... }); Route::middleware(['role:manager|writer'])->group(function () { ... }); Route::middleware(['role_or_permission:manager|edit articles'])->group(function () { ... });

// With specific guard Route::middleware(['role:manager,api'])->group(function () { ... });

For single permissions, Laravel's built-in can middleware also works:

Route::middleware(['can:edit articles'])->group(function () { ... });

Blade Directives

Prefer @can (permission-based) over @role (role-based):

@can('edit articles') {{-- User can edit articles (supports Super Admin) --}} @endcan

@canany(['edit articles', 'delete articles']) {{-- User can do at least one --}} @endcanany

@role('admin') {{-- Only use for super-admin type checks --}} @endrole

@hasanyrole('writer|admin') {{-- Has writer or admin --}} @endhasanyrole

Super Admin

Use Gate::before in AppServiceProvider::boot() :

use Illuminate\Support\Facades\Gate;

public function boot(): void { Gate::before(function ($user, $ability) { return $user->hasRole('Super Admin') ? true : null; }); }

This makes $user->can() and @can always return true for Super Admins. Must return null (not false ) to allow normal checks for other users.

Policies

Use $user->can() inside policy methods to check permissions:

class PostPolicy { public function update(User $user, Post $post): bool { if ($user->can('edit all posts')) { return true; }

    return $user->can('edit own posts') && $user->id === $post->user_id;
}

}

Enums

enum RolesEnum: string { case WRITER = 'writer'; case EDITOR = 'editor'; }

enum PermissionsEnum: string { case EDIT_POSTS = 'edit posts'; case DELETE_POSTS = 'delete posts'; }

// Creation requires ->value Permission::findOrCreate(PermissionsEnum::EDIT_POSTS->value, 'web');

// Most methods accept enums directly $user->assignRole(RolesEnum::WRITER); $user->hasRole(RolesEnum::WRITER); $role->givePermissionTo(PermissionsEnum::EDIT_POSTS); $user->hasPermissionTo(PermissionsEnum::EDIT_POSTS);

Seeding

Always flush the permission cache when seeding:

class RolesAndPermissionsSeeder extends Seeder { public function run(): void { // Reset cache app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

    // Create permissions
    Permission::findOrCreate('edit articles', 'web');
    Permission::findOrCreate('delete articles', 'web');

    // Create roles and assign permissions
    Role::findOrCreate('writer', 'web')
        ->givePermissionTo(['edit articles']);

    Role::findOrCreate('admin', 'web')
        ->givePermissionTo(Permission::all());
}

}

Teams (Multi-Tenancy)

Enable in config/permission.php before running migrations:

'teams' => true,

Set the active team in middleware:

setPermissionsTeamId($teamId);

When switching teams, unset cached relations:

$user->unsetRelation('roles')->unsetRelation('permissions');

Events

Enable in config/permission.php :

'events_enabled' => true,

Available events: RoleAttachedEvent , RoleDetachedEvent , PermissionAttachedEvent , PermissionDetachedEvent in the Spatie\Permission\Events namespace.

Performance

  • Permissions are cached automatically. The cache is flushed when roles/permissions change via package methods.

  • After direct DB operations, flush manually: app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions()

  • For bulk seeding, use Permission::insert() for speed, but flush the cache afterward.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

livewire-development

No summary provided by upstream source.

Repository SourceNeeds Review
199-spatie
Coding

pest-testing

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

tailwindcss-development

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

flare

No summary provided by upstream source.

Repository SourceNeeds Review