Laravel 12 Roles and Permissions Tutorial using Spatie and Breeze

Laravel 12 Roles and Permissions Tutorial using Spatie and Breeze

Introduction

In this tutorial, you'll learn how to implement a Role-Based Access Control (RBAC) system in Laravel 12, step by step. We’ll use two powerful tools to achieve this:

  • Laravel Breeze – A lightweight and minimal authentication starter kit that sets up login, registration, and password reset functionality with a clean setup.

  • Spatie Laravel Permission – A widely-used package that simplifies the management of roles and permissions in Laravel applications.

By the end of this tutorial, you'll have a fully functional authentication system with role and permission-based access control integrated into your Laravel 12 project.

Prerequisites

Before you begin, ensure that you have the following:

  • A Laravel 12-compatible development environment, including:

    • PHP 8.1 or higher

    • Composer

    • Node.js and npm

  • A basic understanding of Laravel and the Model-View-Controller (MVC) architectural pattern.

Step 1: Create a New Laravel 12 Project

Run the following command in your terminal:

composer create-project laravel/laravel laravel-spatie-auth

This installs a fresh Laravel 12 project.

Step 2: Install Laravel Breeze Authentication Starter Kit

Laravel Breeze provides simple auth scaffolding, including login, registration, and password reset.

Install Breeze with:

composer require laravel/breeze --dev php artisan breeze:install

When run php artisan breeze:install In Laravel 12:

┌ Which Breeze stack would you like to install? ───────────────┐ │ › ● Blade with Alpine │ │ ○ Livewire (Volt Class API) with Alpine │ │ ○ Livewire (Volt Functional API) with Alpine │ │ ○ React with Inertia │ │ ○ Vue with Inertia │ │ ○ API only │ └──────────────────────────────────────────────────────────────┘
Would you like dark mode support? ───────────────────────────┐ Yes / No └──────────────────────────────────────────────────────────────┘
┌ Which testing framework do you prefer? ──────────────────────┐ │ › ● Pest │ │ ○ PHPUnit │ └──────────────────────────────────────────────────────────────┘

Then install node dependencies and compile assets:

npm install npm run dev

Update .env to connect with your database:

DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=laravel_db DB_USERNAME=root DB_PASSWORD=

Run migrations for Breeze auth tables:

php artisan migrate
WARN The database 'laravel_db' does not exist on the 'mysql' connection. ┌ Would you like to create it? ────────────────────────────────┐ │ ● Yes / ○ No │ └──────────────────────────────────────────────────────────────┘

means Laravel detected your database laravel_db does not exist yet, and it’s asking if you want to create it automatically.

Start the server:

php artisan serve 

Visit http://localhost:8000 to see the auth system in action.

Step 3: Install Spatie Laravel Permission Package

Spatie's package manages roles and permissions cleanly.

Install it via composer:

composer require spatie/laravel-permission

Step 4: Publish Spatie Config and Migration Files

Publish the config file and migrations:

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

This publishes:

  • config/permission.php

  • migrations for roles, permissions, and pivot tables.

Step 5: Run Migrations for Roles & Permissions

Apply the migrations to create the required tables:

php artisan migrate

Step 6: Add HasRoles Trait to User Model

Open app/Models/User.php and add:

use Spatie\Permission\Traits\HasRoles; class User extends Authenticatable { use HasRoles; // other model properties and methods }

This enables role and permission methods on the User model.

Step 7: Create Seeder for Roles and Permissions

Create a seeder:

php artisan make:seeder RolePermissionSeeder

Edit database/seeders/RolePermissionSeeder.php:

<?php namespace Database\Seeders; use Illuminate\Database\Seeder; use Spatie\Permission\Models\Role; use Spatie\Permission\Models\Permission; class RolePermissionSeeder extends Seeder { public function run() { // Clear cached roles and permissions app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions(); // Define permissions Permission::create(['name' => 'view posts']); Permission::create(['name' => 'create posts']); Permission::create(['name' => 'edit posts']); Permission::create(['name' => 'delete posts']); // Create roles $admin = Role::create(['name' => 'admin']); $editor = Role::create(['name' => 'editor']); $viewer = Role::create(['name' => 'viewer']); // Assign permissions to roles $admin->givePermissionTo(Permission::all()); $editor->givePermissionTo(['view posts', 'create posts', 'edit posts']); $viewer->givePermissionTo(['view posts']); } }

Step 8: Seed the Database

Run the seeder:

php artisan db:seed --class=RolePermissionSeeder

Step 9: Assign Roles to Users

You can assign roles in a controller, seeder, or manually using Tinker.

Example using Tinker:

php artisan tinker

Inside Tinker:

$user = \App\Models\User::find(1); // Replace with real user ID $user->assignRole('admin'); exit;

Roles are stored in the roles table by default

  • This table contains columns like idnameguard_namecreated_at, and updated_at.

  • Example data:

idnameguard_namecreated_atupdated_at
1adminweb2025-06-20 12:00:002025-06-20 12:00:00
2editorweb2025-06-20 12:10:002025-06-20 12:10:00
3viewerweb2025-06-20 12:15:002025-06-20 12:15:00

Step 10: Use Blade Directives for Role/Permission Checks

File: resources/views/dashboard.blade.php

<x-app-layout> <x-slot name="header"> <h2 class="font-semibold text-xl text-gray-800 leading-tight"> {{ __('Dashboard') }} </h2> </x-slot> <div class="py-12"> <div class="max-w-7xl mx-auto sm:px-6 lg:px-8"> <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg"> <div class="p-6 text-gray-900"> <p>{{ __("You're logged in!") }}</p> @php // Retrieve the first role name assigned to the authenticated user $role = auth()->user()->getRoleNames()->first(); @endphp @if($role) <p class="mt-4"> {{ __("You're logged in as") }} <strong class="text-green-600">{{ ucfirst($role) }}</strong>! </p> @else <p class="mt-4 text-red-600"> {{ __("You're logged in but no role has been assigned.") }} </p> @endif </div> </div> </div> </div> </x-app-layout>

Step 11: (Optional) Clear Permission Cache After Changes

If you add or update permissions or roles, clear the cache:

php artisan permission:cache-reset

Summary

You now have a Laravel 12 app with:

  • Authentication by Breeze

  • Roles and permissions by Spatie

  • Route protection and UI conditional rendering

This is a solid foundation for RBAC in Laravel.

Souy Soeng

Souy Soeng

Hi there 👋, I’m Soeng Souy (StarCode Kh)
-------------------------------------------
🌱 I’m currently creating a sample Laravel and React Vue Livewire
👯 I’m looking to collaborate on open-source PHP & JavaScript projects
💬 Ask me about Laravel, MySQL, or Flutter
⚡ Fun fact: I love turning ☕️ into code!

Post a Comment

CAN FEEDBACK
close