spatie/laravel-permission is the most widely adopted role and permission package for Laravel — it adds roles and granular permissions on top of Laravel's own auth system rather than replacing it.
1. Install and set up
composer require spatie/laravel-permission
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
php artisan migrate
Add the trait to your User model:
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasRoles;
}
2. Create roles and permissions
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
$editorRole = Role::create(['name' => 'editor']);
$permission = Permission::create(['name' => 'edit articles']);
$editorRole->givePermissionTo($permission);
3. Assign roles to users
$user->assignRole('editor');
$user->givePermissionTo('publish articles'); // direct permission, no role needed
Permissions can be assigned directly to a user, or granted implicitly through a role — a user has a permission if it's attached directly OR through any role they hold.
4. Checking permissions in code
if ($user->can('edit articles')) {
// ...
}
if ($user->hasRole('editor')) {
// ...
}
5. In Blade templates
@can('edit articles')
<a href="https://readerstacks.com/articles/{{ $article->id }}/edit">Edit</a>
@endcan
6. Gating routes with middleware
Route::middleware(['role:editor'])->group(function () {
Route::get('/admin/articles', [ArticleController::class, 'index']);
});
Route::middleware(['permission:publish articles'])->group(function () {
Route::post('/articles/{article}/publish', [ArticleController::class, 'publish']);
});
Roles vs. direct permissions — when to use which
Roles are the right tool when a group of permissions genuinely travels together (an "editor" always gets the same bundle of abilities). Direct permissions are better for one-off exceptions — granting a single extra permission to one specific user without creating a whole new role just for them.