L LAB

Roles & Permissions (RBAC)

Role-based access control via Laratrust v8. Defaults are seeded from config/boilerplate.php, new users are auto-assigned a role on registration, and the standard role: / permission: middleware integrate with the JSON error envelope.

Out of the box

Rolesadmin, user
Default role on registeruser
Permissionsusers.read, users.write, roles.read, roles.write
adminall permissions (*)
usernone

These are starting points — edit config for your domain.

Configuration

'rbac' => [
    'enabled' => env('RBAC_ENABLED', true),
    'default_role' => env('RBAC_DEFAULT_ROLE', 'user'),

    'permissions' => [
        ['name' => 'users.read',  'display_name' => 'View Users'],
        ['name' => 'users.write', 'display_name' => 'Manage Users'],
    ],
    'roles' => [
        ['name' => 'admin', 'display_name' => 'Administrator', 'permissions' => ['*']],
        ['name' => 'user',  'display_name' => 'User',          'permissions' => []],
    ],
],
KeyEffect
enabled = falseSeeder is a no-op; registration doesn’t auto-assign.
default_role = nullDisable auto-assignment without disabling RBAC.
roles[].permissionsList of permission names; ['*'] grants all.

Seeder

RolesAndPermissionsSeeder upserts roles & permissions and syncs each role’s list. Idempotent — safe on every deploy, and run by migrate --seed.

php artisan db:seed --class=RolesAndPermissionsSeeder

Route middleware

// Single role
Route::middleware(['auth:sanctum', 'role:admin'])->get('/admin/users', ...);

// Single permission
Route::middleware(['auth:sanctum', 'permission:users.write'])->post('/users', ...);

// Any of multiple roles (OR)
Route::middleware(['auth:sanctum', 'role:admin|editor'])->get('/dashboard', ...);

// All of multiple permissions (AND)
Route::middleware(['auth:sanctum', 'permission:users.read|users.write|require_all'])->put('/users/{id}', ...);

A failed check raises HttpException(403), rendered as the standard JSON envelope:

{ "message": "User does not have any of the necessary access rights." }

Programmatic checks

$user->hasRole('admin');
$user->hasRole('admin|editor');           // any (OR)
$user->isAbleTo('users.write');           // permission via role or direct
$user->addRole('admin');
$user->syncRoles(['user', 'editor']);
$user->givePermission('users.write');     // direct grant (bypasses roles)

Default-role assignment

On register / first OTP / social signup, the Registered event triggers the AssignDefaultRole listener. It runs synchronously (so the role is attached before the response returns) and only acts when RBAC is enabled, default_role is set, and the role exists. A missing role logs a warning and is skipped — registration still succeeds.

Caching

Laratrust caches lookups when LARATRUST_ENABLE_CACHE=true (default in production). After mutating roles/permissions in production, call $user->flushCache().