wnikk/laravel-access-rules
| Install | |
|---|---|
composer require wnikk/laravel-access-rules |
|
| Latest Version: | 3.1.2 |
| PHP: | ^8.4 |
| License: | MIT |
| Last Updated: | Sep 22, 2026 |
| Links: | GitHub · Packagist |

Access Control Rules: RBAC and ABAC for Laravel
Roles, groups and inheritance (RBAC), and since version 3 permissions that depend on data (ABAC), through the standard Laravel Gate.
$user->addPermission('orders.view'); // RBAC: may or may not
$user->addPermission('orders.export', when: 'order.cost > 100 && order.items.count < 3'); // ABAC: depends on the record
A check costs 4 µs and no queries after the first one of a request, and the database filters a list in the same query that loads it.
Background. The model of this package has run in production since 2013: first on Zend Framework, then on Yii2, since 2023 as this Laravel package. Its parts are a separate owner with dynamic binding, inheritance of any depth, hybrid rules and options. The Laravel version keeps the number of classes low and uses what Laravel already has, so a check passes through little code.
Contents
| If you want to | read |
|---|---|
| see what it looks like | What it does, What ABAC can do |
| decide between packages | When to choose it, and when not, Alternatives, measured numbers |
| install and start | Installation, Basic usage, Conditions (ABAC) |
| learn by example | ABAC step by step, RBAC step by step |
| come from version 2 | Upgrade from 2.x to 3.x: tables and the API stay compatible |
| exchange policies | XACML 3.0 |
| work with an AI coding agent | For AI coding agents, docs/llms.txt |
What does Access Control Rules support?
New in version 3
- Conditions (ABAC): a permission or a prohibition can depend on the record, its relations of any kind and their aggregates, on the user and on the environment.
- Filtering of lists by the same conditions, in the same query:
Order::query()->allowedTo('orders.view'). A list and a detail page read one condition, so they agree. - A language for conditions: arithmetic,
between, exact text functions, aggregates with filters over any relation, columns of pivot tables, time functions, and trees: "this category and everything under it". - Safe to edit in an admin panel: a condition is checked when it is saved, reads only models listed in config and never calls a method of a model that is not a relation.
- No queries after the first check of a request: 4 µs per check against 62 µs and a query in version 2; permissions compile in 3 queries at any depth of inheritance. See Performance.
acr:explaintells why a check answers what it answers,acr:lintfinds stored conditions that a migration or a refactoring has broken.- Debug mode for support sessions:
Access::debug()explains every refusal and records what narrowed everyallowedTo()list. It observes; decisions stay as they are. - XACML 3.0: export of permissions as a standard policy, import of policies with a plan of what would change. A check runs no XACML engine.
- Guests, tenants, abilities as enums, the
Accessfacade, rules of code and rules of an admin panel, eventAccessChangedfor an audit log. - Guidelines and a skill for AI coding agents through Laravel Boost.
Since version 2
- Multiple user models, roles, groups and any other owners of permissions, also without a model.
- Permissions and prohibitions, attached to users, groups or roles.
- Permissions can be inherited with unlimited nesting from users, groups and roles.
- Dynamic options (
news.edit.2) and the magic suffix.selffor authors of records. - Laravel gates and policies:
$user->can(),@can,can:middleware,authorizeResource(). The package answers Gate with "yes" or nothing, so policies, a super administrator of the application and other packages keep working next to it. - Permissions caching, with a fallback to the database when the cache store is down.
What ABAC can do
An example of what the requirements might be:
Show the user all products tagged "sale" that have a comment with more than 10 likes.
Every link is polymorphic: likes belong to comments and comments to products through morphMany,
tags reach products through morphToMany.
Setting this permission:
$user->addPermission('products.view',
when: "exists(product.tags, name == 'sale') && exists(product.comments, likes.count > 10)");
The check in the controller:
$user->can('products.view', $product); // one loaded product, checked in memory
# -- or --
Product::query()->allowedTo('products.view')->paginate(); // the list, filtered by the database:
The SQL query generated by the model, taking into account controller parameters and access rights:
select * from "products" where (
exists (select 1 from "tags" inner join "taggables" on "tags"."id" = "taggables"."tag_id"
where "products"."id" = "taggables"."taggable_id" and "taggables"."taggable_type" = ? and "tags"."name" = ?)
and exists (select 1 from "comments"
where "products"."id" = "comments"."commentable_id" and "comments"."commentable_type" = ?
and (select count(*) from "likes"
where "comments"."id" = "likes"."likeable_id" and "likes"."likeable_type" = ?) > ?))
-- bindings: ["product", "sale", "product", "comment", 10]
The configuration itself that makes such rules possible:
// config/access.php: every model a condition may read
'resources' => ['product' => Product::class, 'comment' => Comment::class, 'like' => Like::class, 'tag' => Tag::class],
// Migration or seeder: create the permission with a resource
Access::newRule('products.view', 'View products', resource: 'product');
Any tag under "sale" instead of "sale" itself: exists(product.tags, id in below('tag.name', 'sale')).
The language, relations, aggregates and trees are described in Conditions.
Visual Interface
The visual interface for managing access control rules and permissions can be found at this link. It offers an intuitive and user-friendly environment for administrators to define roles, assign permissions, and configure access rules.
For detailed usage examples and instructions, refer to the example repository.
Documentation
Installation · Basic usage · Conditions (ABAC) · Performance · XACML · Upgrade from 2.x to 3.x
Tutorials: RBAC step by step, ABAC step by step.
Versions & Dependencies
| Laravel Access Control Rules | PHP | Laravel | Model |
|---|---|---|---|
| 3.x | 8.4+ | 13+ | RBAC + ABAC |
| 2.x | 7.4 - 8.4 | 8 - 13 | RBAC + Dynamic option |
| 1.x | 7.1 - 7.3 | 5.5 - 8 | RBAC |
Installation
composer require wnikk/laravel-access-rules
For Laravel 12 and older stay on 2.x: composer require wnikk/laravel-access-rules:^2.4.
See the installation page for detailed.
What It Does
This package allows you to manage user permissions and groups (instead roles) in a database.
Once installed you can do stuff like this:
use Wnikk\LaravelAccessRules\Facades\Access;
// Add new rule permission
Access::newRule('articles.edit', 'Access to editing articles');
// Adding permissions to a user
$user->addPermission('articles.edit');
Or you can inherit the rights from another user or groups
// According to the existing user from object
$user->inheritPermissionFrom(User::find(1));
// By identifier
$user->inheritPermissionFrom(User::class, 1);
// From the group
$user->inheritPermissionFrom('Group', 1);
Because all permissions will be registered on Laravel's gate, you can check if a user has a permission with Laravel's default can function:
$user->can('articles.edit');
Or without model:
$check = Access::for('AnotherAnySystemUser', 'UserID-From-Any-System-FF01')->can('articles.edit');
if (!$check) {abort(403);}
Examples of how can be used in more detail described in Basic Usage section.
When to choose it, and when not
Choose it when:
- access depends on data: "orders of my department", "up to my approval limit, but not my own", "clients with a turnover above 1000, except city Y", and the same rule has to filter lists;
- roles inherit from roles to any depth, or users inherit from users and groups;
- you need prohibitions on top of roles, and one user has to get back what a role took away;
- owners of permissions are not only users: roles, groups, teams, API clients, records of another system;
- every request makes many checks: menus, tables with buttons per row, API resources;
- an administrator edits access at run time and must not be able to break the application with a typo;
- a user asks "why can't I see it?" and you need the answer in a minute;
- you hand policies to an auditor or another system as XACML.
Look elsewhere when:
- access is a short, fixed list of role names checked in code, and nothing depends on data. A plain role package or Laravel policies alone are less to learn;
- you are on Laravel 12 or older and need ABAC. Version 3 needs Laravel 13 and PHP 8.4; version 2 is RBAC only.
Alternatives
| this package | spatie | bouncer | |
|---|---|---|---|
| Roles and direct permissions | yes | yes | yes |
| Roles inherit from roles | yes, any depth | no, roles are flat | no |
| Prohibitions | yes, with a five-step priority | no | yes (forbid) |
| Owners without a model | yes | no | no |
| Permission depends on data of the record | yes: columns, relations, aggregates, the user, time | no, write a policy | ownership and single instances |
| Lists filtered by the same rules, in SQL | yes, allowedTo() |
no | no |
| "Why was it refused?" | acr:explain, debug mode |
no | no |
| Stored rules checked against code | acr:lint |
no | no |
| XACML export and import | yes | no | no |
| Teams / tenants | yes, through inheritance and user.tenant |
yes, teams | yes, scopes |
Measured on one machine with the same data (MySQL, 2 000 abilities, the user holds 500 of them, one request of a signed-in user):
| this package | spatie | bouncer | |
|---|---|---|---|
| first check of a request | 0.2 ms, 0 queries, 51 KB | 5.0 ms, 2 queries, 3.9 MB | 4.2 ms, 0 queries |
| next check, permitted | 4.0 µs | 28.9 µs | 4 169 µs |
| next check, not permitted | 4.1 µs | 1 461 µs | 4 198 µs |
| a page with 50 checks | 0.2 ms | 2.5 ms | 207 ms |
Versions, the method, a smaller data set and what these numbers do not say are in Performance.
Authentication, API tokens and social login belong to other packages. This one decides what a signed-in user may do.
For AI coding agents
The package ships Laravel Boost guidelines and a skill in resources/boost/.
php artisan boost:install asks which third-party packages to include: tick wnikk/laravel-access-rules, and Boost
adds the guidelines to CLAUDE.md / AGENTS.md of your application and installs the skill access-rules-development.
With Boost already installed, run php artisan boost:update --discover. docs/llms.txt
is a map of the documentation, and AGENTS.md is for agents that work on the package itself.
They tell an agent to check through Gate, to write data-dependent access as a condition instead of a policy plus
a hand-written query, to filter lists with allowedTo() and to create rules in migrations.
Opening an Issue
Before opening an issue there are a couple of considerations:
- You are all awesome!
- Pull requests are more than welcome.
- Read the instructions and make sure all steps were followed correctly.
- Check that the issue is not specific to your development environment setup.
- Provide duplication steps.
- Attempt to look into the issue, and if you have a solution, make a pull request.
- Show that you have made an attempt to look into the issue.
- Check to see if the issue you are reporting is a duplicate of a previous reported issue.
- Following these instructions show me that you have tried.
- Please be considerate that this is an open source project that I provide to the community for FREE when opening an issue.
License
The MIT License (MIT). Please see License File for more information.
Related Packages
Role-based access control for Laravel — roles with hierarchy, permissions, Blade...
The most advanced enterprise-grade permission management system for Laravel. RBA...