NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Permissions for Laravel

The Permissions facade

Everything goes through the Permissions facade (auto-aliased as Permissions). Its root is RoundlyConsulting\Permissions\PermissionsManager, a singleton you can also inject. Every name-taking method accepts a string or a BackedEnum:

use RoundlyConsulting\Permissions\Facades\Permissions;

// Catalog
Permissions::role('editor');                       // find or create — Role
Permissions::permission('posts.edit');             // find or create — Permission
Permissions::findRole('editor');                   // ?Role
Permissions::findPermission('posts.edit');         // ?Permission — the full row
Permissions::roles();                              // Collection<Role>, ordered by name
Permissions::permissions();                        // the cached catalog: id + name
Permissions::exists('posts.edit');                 // bool, from the cache
Permissions::syncFrom(PostPermission::class);      // SyncResult
Permissions::syncRolesFrom(RoleName::class);       // SyncResult

// Grants for one holder — every verb returns the holder
Permissions::for($user)->assignRole('editor');
Permissions::for($user)->removeRole('editor');
Permissions::for($user)->syncRoles(['editor']);
Permissions::for($user)->givePermissionTo('posts.edit');
Permissions::for($user)->revokePermissionTo('posts.edit');
Permissions::for($user)->syncPermissions([PostPermission::Edit]);
Permissions::for($user)->forgetAllAuthorization();

// Housekeeping and configuration
Permissions::cache()->forget();
Permissions::cache()->flushMemo();
Permissions::pruneOrphans();                       // int — rows deleted
Permissions::roleModel();                          // class-string<Role>
Permissions::permissionModel();                    // class-string<Permission>

// Tests
$fake = Permissions::fake();                       // PermissionsFake

Methods

MethodReturnsPurpose
role($name)RoleFind or create a role, as your configured model.
permission($name)PermissionFind or create a permission, as your configured model.
findRole($name)?RoleLook a role up by name; null when missing. A live query.
findPermission($name)?PermissionLook a permission up by name — the full row, description included.
roles()Collection<Role>Every role, ordered by name. A live query.
permissions()Collection<Permission>The cached permission catalog — id and name only.
exists($name)boolWhether a permission is registered, answered from the cache.
syncFrom(Enum::class)SyncResultRegister one permission per case of a backed enum. Additive.
syncRolesFrom(Enum::class)SyncResultRegister one role per case of a backed enum. Additive.
for($holder)HolderGrantsRole and permission writes scoped to one holder.
cache()PermissionCacheforget() drops the cached catalog; flushMemo() drops only this process’s memo.
pruneOrphans()intDelete grant rows whose holder no longer exists; returns the count.
roleModel() / permissionModel()class-stringYour configured model classes.
fake()PermissionsFakeSwap in the recording fake — facade only.

Writes for one holder: for()

Permissions::for($holder) returns a HolderGrants handle with the same write verbs as the traits. Every verb returns the holder:

use RoundlyConsulting\Permissions\Facades\Permissions;

Permissions::for($user)->assignRole('editor');
Permissions::for($user)->syncPermissions([PostPermission::Edit]);

$role = Permissions::role('editor');
Permissions::for($role)->givePermissionTo('posts.edit'); // a Role holds permissions

// The trait methods are sugar over the same handle:
$user->assignRole('editor'); // === Permissions::for($user)->assignRole('editor')
Permissions::for($holder)->…DoesHolder must
assignRole(...$roles)Additively assign roles.use HasRoles
removeRole(...$roles)Detach roles.use HasRoles
syncRoles($roles)Make the given roles the exact set.use HasRoles
givePermissionTo(...$permissions)Additively grant direct permissions.use HasPermissions — a Role or any HasRoles model
revokePermissionTo(...$permissions)Detach direct permissions.use HasPermissions
syncPermissions($permissions)Make the given direct permissions the exact set.use HasPermissions
forgetAllAuthorization()Detach every role and direct permission.use HasRoles

The scope is a boundary. Role writes refuse a model without HasRoles — including a Role, which holds permissions, never roles. Permission writes refuse a model without HasPermissions, and both refuse a holder that has no key yet. Each refusal is a PermissionException, thrown before anything is written; unknown names throw RoleDoesNotExist or PermissionDoesNotExist.

Where each part is documented

  • role(), permission(), findRole(), findPermission(), roles() — Roles & permissions.
  • syncFrom(), syncRolesFrom() — Backed enums.
  • for()->… role verbs — Assigning roles; permission verbs — Granting permissions.
  • permissions(), exists(), cache() — Caching.
  • pruneOrphans() — Deleting holders.
  • fake() — Testing.

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.