Laravel 13 Roles & Permissions with Spatie - Step by Step

February 12, 2025 · 5 min read

2026 UPDATE - LARAVEL 13
We’re excited to announce that we have updated all of our blog post examples to reflect the new Laravel 13 version! Our previous examples were based on Laravel 10, but with the release of Laravel 13, we wanted to ensure that our readers have access to the most up-to-date information and examples.
Roles and Permissions in Laravel 13
Laravel is known for its simplicity and elegance in building modern web apps. One key feature is its roles and permissions system, which helps control user access and keeps your app secure. This guide explores what roles and permissions are, why they matter, and how to use them in Laravel 13.
What Are Roles and Permissions?
Roles
In Laravel, a role is a label given to a user that defines their access level in the app. For example, you might have roles like "admin," "editor," or "user." Each role is linked to a set of permissions that specify what actions the user can perform.
Permissions
Permissions are actions users can perform, such as "manage users" or "edit posts." They help you control exactly what each role can do.
Using roles and permissions is important for keeping your app secure and organized. Here’s why:
Scalability: As your app grows, managing user access individually becomes difficult. Roles and permissions provide a scalable way to handle access control.
Security: By clearly defining what each role can and cannot do, you reduce the risk of unauthorized access to sensitive parts of your app.
Maintainability: A well-defined roles and permissions system makes it easier to update and manage user access as your app evolves.

Using Roles and Permissions in Laravel 13
Step 1: Installing the Laravel Authorization Package
Laravel 13 has built-in support for roles and permissions. To make the tutorial simpler, we will use the Spatie Laravel-Permission package. It’s the most used package in Laravel for roles and permissions.
To install the package, run:
composer require spatie/laravel-permission
After installation, publish the migration files and run the migrations:
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
php artisan migrateBuilding a Laravel app that needs roles and permissions?
Lucky Media builds custom backends for startups and enterprises. Let's talk
Step 2: Setting Up Models and Relationships
Next, set up the necessary relationships in your User model. Add the HasRoles trait provided by the Spatie package:
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasRoles;
// Your existing code...
}This trait adds methods to assign and check roles and permissions for the user.
Step 3: Creating Roles and Permissions
Now that everything is set up, you can create roles and permissions using Artisan commands or directly in your code. For example, you can create roles and permissions in a seeder with the command we already know:php artisan make:seeder RolesAndPermissionsSeeder
Now you can modify the RolesAndPermissionsSeeder.php file to match the following:
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
class RolesAndPermissionsSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// Create roles
$adminRole = Role::create(['name' => 'admin']);
$editorRole = Role::create(['name' => 'editor']);
$userRole = Role::create(['name' => 'user']);
// Create permissions
$viewPosts = Permission::create(['name' => 'view posts']);
$editPosts = Permission::create(['name' => 'edit posts']);
$deletePosts = Permission::create(['name' => 'delete posts']);
}
}Step 4: Assigning Roles and Permissions to Users
We can assign roles and permissions to users using the methods provided by the HasRoles trait:
// Find a user and assign a role
$user = User::find(1);
$user->assignRole('admin');There are different ways how you can implement this in your app, we believe it’s enough to show how you make the actual connection with the code we just provided.
Let’s modify the seeder we just created to automatically seed some roles to our users:
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
use App\Models\User;
class RolesAndPermissionsSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
// Create roles
$adminRole = Role::create(['name' => 'admin']);
$editorRole = Role::create(['name' => 'editor']);
$userRole = Role::create(['name' => 'user']);
// Create permissions
$viewPosts = Permission::create(['name' => 'view posts']);
$editPosts = Permission::create(['name' => 'edit posts']);
$deletePosts = Permission::create(['name' => 'delete posts']);
// Assign permissions to roles
$adminRole->givePermissionTo([$viewPosts, $editPosts, $deletePosts]);
$editorRole->givePermissionTo([$viewPosts, $editPosts]);
$userRole->givePermissionTo($viewPosts);
// Get all users
$users = User::all();
// Assign roles based on the user's position in the list
foreach ($users as $index => $user) {
// First three users will be admins
if ($index < 3) {
$user->assignRole('admin');
}
// The following three users will be editors
elseif ($index < 6) {
$user->assignRole('editor');
}
// The rest will have the role user
else {
$user->assignRole('user');
}
}
}
}You can also check if a user has a specific role or permission. Let’s modify our existing PostController to do the following restrictions:
Only admins can delete posts, but not editors and users.
Admins and editors can edit articles, but not users.
Everyone (users, editors, and admins) will be able to view a single post.
We can do this either by checking the role or by checking the permission of the authenticated user. As for editing posts, we showed 2 ways to do the same thing. To view the edit post page we will check if the user has the role of admin or editor. To update the post we check if the permission of that user has edit posts. If not, we will redirect the user to the post-show page.
namespace App\Http\Controllers;
use App\Events\PostPublished;
use App\Jobs\SendNewPostNotification;
use App\Mail\NewPostPublished;
use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
class PostController extends Controller
{
// Display a single blog post
public function show($id)
{
// Check if user has permission to view post
if (!auth()->user()->can('view posts')) {
return redirect()->route('posts.index');
}
$post = Post::with('user', 'tags', 'images')
->findOrFail($id);
return view('posts.show', ['post' => $post]);
}
// Show a form for editing the specified blog post
public function edit($id)
{
// Check if user has the admin or editor role
if (!auth()->user()->hasRole(['admin', 'editor'])) {
return redirect()->route('posts.show', $post);
}
$post = Post::findOrFail($id);
$tags = Tag::all();
return view('posts.edit', ['post' => $post, 'tags' => $tags]);
}
// Update the specified blog post
public function update(Request $request, Post $post)
{
// Check if user has permission to edit posts
if (!auth()->user()->can('edit posts')) {
return redirect()->route('posts.show', $post);
}
$validatedData = $request->validate([
'title' => 'required|max:255',
'content' => 'required',
// other validation rules...
]);
$tags = $request->validate([
'tags' => 'required',
]);
$post->update($validatedData);
// we modify the tags of the post by using the sync() method
$post->tags()->sync($tags);
return redirect()->route('posts.show', $post);
}
// Delete a blog post
public function destroy(Post $post)
{
// Check if user is an admin
if (!auth()->user()->hasRole('admin'])) {
return redirect()->route('posts.show', $post);
}
$post->delete();
return redirect()->route('posts.index');
}
}To do it by checking the role of the authenticated user we should use:
// Check if user is an admin
if (!auth()->user()->hasRole('admin')) {
return redirect()->route('posts.show', $post);
}To do it by checking the permission of the authenticated user we should use:
// Check if user has permission to edit posts
if (!auth()->user()->can('edit posts')) {
return redirect()->route('posts.show', $post);
}Step 5: Protecting Routes with Roles and Permissions
Laravel’s middleware makes it easy to protect routes based on roles and permissions. You can use the role and permission middleware provided by the Spatie package. This will help you protect individual routes or you can also group routes with the same protection rules.
// We need to use this example in the blog post example that we have
Route::group(['middleware' => ['role:admin']], function () {
Route::get('/admin', function () {
// Only accessible by admins
});
});
Route::group(['middleware' => ['permission:edit posts']], function () {
Route::get('/posts/{post}', function () {
// Only accessible by users with 'edit posts' permission
});
});
Conclusion
Roles and permissions are important for secure user access in Laravel apps. With Laravel 13 and the Spatie package, you can easily manage access and build a secure, scalable app. By following the steps in this guide, you’ll be on your way to building a secure and scalable app.
Upcoming Articles in the Series
Laravel for Beginners: Differences of using Policies vs Roles and Permissions
Laravel for Beginners: Using Laravel Spark with Stripe and Paddle
This article is part of our series Laravel for Beginners: A Step-by-Step Guide to Learn the Concepts.
Bring Your Ideas to Life 🚀
If you need help with a Laravel project let’s get in touch.
Lucky Media is proud to be recognized as a leading Laravel Development Agency
Technologies

Stay up-to-date
Be updated with all news, products and tips we share!
On this page
- 2026 UPDATE - LARAVEL 13
- Roles and Permissions in Laravel 13
- What Are Roles and Permissions?
- Using Roles and Permissions in Laravel 13
- Step 1: Installing the Laravel Authorization Package
- Step 2: Setting Up Models and Relationships
- Step 3: Creating Roles and Permissions
- Step 4: Assigning Roles and Permissions to Users
- Step 5: Protecting Routes with Roles and Permissions
- Conclusion
- Upcoming Articles in the Series
- Bring Your Ideas to Life 🚀

