Currently Available: Need a skilled Software Developer for your next project?
Categories
Laravel

How to Assign Roles and Permissions with Spatie Laravel Permission

Spatie Laravel Permission lets your Laravel application control which actions users can perform. A permission names an action, such as edit articles; a role groups permissions, such as editor. Assign permissions to roles, then assign roles to users. Laravel can check the user’s permissions when it handles a request.

Check permissions in your code, and use roles to group them. The sections below show how to install the package, create and assign roles and permissions, and enforce those rules on routes and in views.

Install the package and enable role support

Install the package, publish its configuration and database migrations, then run the migrations:

composer require spatie/laravel-permission

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"

php artisan migrate

The package stores roles, permissions, and their assignments in database tables. The installation steps show how to publish the package files before running the migrations.

Add Spatie’s HasRoles trait to your User model. The trait adds methods such as assignRole() and hasRole() to the model, and enables permission checks for the user.

<?php

namespace App\Models;

use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;

class User extends Authenticatable
{
    use HasRoles;
}

The trait also supports other Eloquent models that need roles, as described in Spatie’s basic usage documentation.

Create permissions and assign them to a role

Create a permission for each action your code must protect, then add those permissions to a role. For example, an editor role could receive permission to edit articles:

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

$editArticles = Permission::create([
    'name' => 'edit articles',
]);

$editor = Role::create([
    'name' => 'editor',
]);

$editor->givePermissionTo($editArticles);

You can also assign the relationship from the permission side with $editArticles->assignRole($editor). To replace a role’s current permission set, use syncPermissions():

Permission::create([
    'name' => 'publish articles',
]);

$editor->syncPermissions([
    'edit articles',
    'publish articles',
]);

When you call syncPermissions(), Spatie sets the role’s permissions to the values you provide and removes any permissions you omit. Use givePermissionTo() when you want to add a permission without replacing the role’s existing set. To remove one permission, call $editor->revokePermissionTo('edit articles').

Spatie recommends using roles to group permissions and checking permissions in code. This ties authorization to actions instead of a user’s job label. The package’s roles-versus-permissions guidance explains this approach.

Assign roles to users

Once the role exists, assign it to a user:

$user->assignRole('editor');

Users can have multiple roles; pass an array to assign several:

Role::create([
    'name' => 'viewer',
]);

$user->assignRole(['editor', 'viewer']);

The user inherits the permissions attached to those roles. You can check a specific role with $user->hasRole('editor'), but check the permission when the code needs to decide whether the user can perform an action:

if ($user->can('edit articles')) {
    // Show or perform the article-editing action.
}

You can assign permissions directly to individual users, but Spatie recommends reserving it for exceptions. Permissions spread across user accounts are harder to manage than permissions assigned through roles.

Enforce permissions on routes and in views

Protect routes on the server so users cannot bypass the rule by entering a URL or calling an endpoint directly. Spatie provides middleware for role checks and permission checks. For example:

use Illuminate\Support\Facades\Route;

Route::middleware(['auth', 'permission:edit articles'])
    ->put('/articles/{article}', [ArticleController::class, 'update']);

Place authorization middleware after auth, so Laravel authenticates the request before checking the user’s permissions. If your Laravel version requires middleware aliases, register Spatie’s aliases in the appropriate bootstrap configuration. In Laravel 13, the aliases belong in bootstrap/app.php; the Laravel permission setup example covers that registration.

Use role:admin|editor to let a user with either listed role pass the check. If a route requires both roles, stack separate role middleware entries:

Route::get('/restricted', RestrictedController::class)
    ->middleware(['auth', 'role:admin', 'role:editor']);

In Blade templates, @can can hide controls a user cannot use, and @role can show content based on a role:

@can('edit articles')
    <a href="{{ route('articles.edit', $article) }}">Edit article</a>
@endcan

@role('admin')
    <a href="{{ route('admin.dashboard') }}">Admin dashboard</a>
@endrole

These checks control what the page displays. The route or controller must still enforce authorization on the server.

Match guards and refresh cached permission data

Laravel uses a guard as the authentication context, such as web or api. Spatie associates each role and permission with a guard, so each role and permission must use the guard that authenticates the user. If your application uses multiple guards, set guard_name when creating records:

$permission = Permission::create([
    'name' => 'edit articles',
    'guard_name' => 'api',
]);

$role = Role::create([
    'name' => 'editor',
    'guard_name' => 'api',
]);

When the guards do not match, authorization checks on API routes fail even if the role assignment looks correct. Check the user’s configured guard and the guard_name values on the role and permission when a permission check unexpectedly returns 403.

Spatie’s methods update its role and permission cache when you create or change records. If you change role or permission data directly in the database, reset the package’s permission cache. Laravel will then read the updated records. Spatie documents this behavior in its permission cache guidance.

What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Email updates

Usually a new article and a few links I found interesting.

No spam. Unsubscribe with one click.

Leave a Reply

Your email address will not be published. Required fields are marked *