Grant is a roles and permissions package for Laravel by Pushpak Chhajed. You define roles and permissions in PHP enums, while the database stores each user's role assignments. Checks go through Laravel's Gate, so existing calls to can(), Gate::authorize(), and Blade's @can work with Grant.
Define access in enums
A permission enum implements Grant's Ability contract, with each backing value registered as an ability in Laravel's Gate. A role enum implements the Role contract and lists the permissions it grants:
use Shipfastlabs\Grant\Ability;use Shipfastlabs\Grant\Role as RoleContract; enum Permission: string implements Ability{ case EditPosts = 'edit-posts'; case ViewReports = 'view-reports'; public function deniedMessage(): string { return 'You are not allowed to do that.'; }} enum Role: string implements RoleContract{ case Editor = 'editor'; case Viewer = 'viewer'; public function permissions(): array { return match ($this) { self::Editor => [Permission::EditPosts], self::Viewer => [Permission::ViewReports], }; }}
Grant uses roles for assignment and permissions for checks. It has no role middleware or @role directive; routes use Laravel's authorization features to check a permission. If you want more background on defining abilities in code, see our article on authorization with backed enums.
Assign global or scoped roles
After adding Grant's HasRoles trait to the user model, you can manage assignments with grant(), revoke(), and syncRoles(). Passing an Eloquent model as on scopes a role to that team, project, or other model:
$user->grant(Role::Editor);$user->grant(Role::Viewer, on: $team); $user->can(Permission::EditPosts);$user->can(Permission::ViewReports, $team);
A scoped permission check includes the user's global roles as well as roles assigned on that model. For another approach to scoped permissions, see Larallow.
Combine permissions with policies
Policies can still handle model rules such as ownership. Grant's Requires attribute checks the permission before the policy method runs, leaving the method to check the post itself:
use Shipfastlabs\Grant\Requires; #[Requires(Permission::EditPosts)]public function update(User $user, Post $post): bool{ return $post->author_id === $user->id;}
Grant forwards Gate arguments to this check, including a model used for scoped roles. You can also configure one role as a super admin; only a globally assigned super admin role bypasses Gate checks.
Install and maintain roles
Grant requires PHP 8.3 or later and Laravel 12 or 13. The install command publishes its configuration and migration, and creates starter role and permission enums if they do not exist:
composer require shipfastlabs/grantphp artisan grant:installphp artisan migrate
After installation, add Shipfastlabs\Grant\HasRoles to the user model. Changing a role's backing value or deleting a case leaves its old assignments orphaned, which means those users lose the role until you remap the rows. Run php artisan grant:sync to remap or delete them; grant:list and grant:show help inspect registered permissions and a user's roles.
See the Grant repository for configuration, testing helpers, and examples of scoped roles.