genealabs/laravel-authorization-addons
GeneaLabs Laravel Authorization Addons extends Laravel's native Gate and policy system with convenient helpers for defining and checking abilities. It streamlines access control across models, controllers, and views, making authorization rules easier to organize and enforce in Laravel applications.
This release is almost entirely a compatibility drop — the package now supports Laravel 13. The version jump from 1.0.1 to 13.0.0 is a renumbering convention (package major now tracks the Laravel major), not twelve breaking releases. Read it that way before you plan upgrade work.
Minimal steps for a fresh install on Laravel 13:
composer require mikebronner/laravel-authorization-addons:^13.0
php artisan vendor:publish # pick the authorization-addons provider/tag
php artisan migrate
Where to look first, in order:
composer.json of the package — confirm the PHP and illuminate/* constraints match your app (Laravel 13 implies a newer PHP floor than the 1.0.1 era).Gate::before hook, config merge, and Blade directives are registered. This is the source of most surprising behaviour.config/authorization-addons.php (name may differ) — role/permission table names, cache TTL, and the super-admin bypass switch.First use case to wire up: add the HasRoles / HasPermissions traits to App\Models\User, seed one role, then protect a route with the package middleware and render a @role-style Blade check in a view. If that round-trips, the integration is sound.
Trait composition on the user model. The traits are the whole API surface for most apps. Put them on User (or a base Authenticatable), then use $user->assignRole(), $user->hasRole(), $user->hasPermissionTo() in controllers and policies. Keep raw DB queries out of authorization code — go through the traits so the package's permission cache stays coherent.
Super-admin bypass at the gate layer. The package typically registers a Gate::before callback so a designated super-admin role passes every check. Use this instead of scattering if ($user->isAdmin()) through policies. Consequence: policies never run for super admins, so don't put audit logging inside a policy and expect it to fire for admins.
Blade directives for view-level gating. Prefer the package's directives over @if(auth()->user()->hasRole(...)) — they're shorter and consistent. But treat them as cosmetics only: every directive must be backed by a middleware or authorize() call, otherwise a crafted request hits the controller anyway.
Route middleware over inline checks. Register the role/permission middleware aliases in bootstrap/app.php (Laravel 11+ style — there is no Http/Kernel.php to edit in a Laravel 13 app):
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'role' => \...\RoleMiddleware::class,
'permission' => \...\PermissionMiddleware::class,
]);
})
Cache-aware role changes. The package caches a user's permissions. Any code path that mutates roles/permissions — seeders, admin panels, queue jobs, impersonation — must go through the trait methods so the cache is flushed. Bulk DB::table('role_user')->insert() will silently leave stale permissions in place.
Testing pattern. Use an in-memory/array cache driver and flush between tests; otherwise a role assigned in test A leaks into test B via the cached permission set. Assert on Gate::allows() / $this->actingAs($user)->get(...) rather than on the trait return values, so you're testing the wiring, not the package internals.
Version pinning as policy. Maintain two constraints in your dependency docs: ^13.0 for Laravel 13 apps, ^1.0 for anything still on Laravel ≤12. Do not attempt to run ^13.0 on an older framework — the constraint won't resolve, and if you force it you're outside the supported matrix.
^1.0 constraint will never see this release. composer update will report "nothing to upgrade." You must edit the constraint explicitly. There is no 2.x–12.x to step through.1.0.1...13.0.0 on GitHub rather than assuming a decade of refactors.require block before upgrading a legacy app, or you'll get a confusing dependency resolution failure that looks like a package bug.Gate::before is a blunt instrument. A super-admin bypass short-circuits every policy, including viewAny on sensitive resources. If you need "admin can do most things but not delete audit logs," that's an explicit Gate::define deny or a policy, not the bypass.@role / hasPermissionTo inside a loop over users triggers a query (or cache hit) per row. Eager-load roles and permissions for admin listings.app/Http/Kernel.php, which doesn't exist in a modern Laravel skeleton. Translate them into bootstrap/app.php.@role, the last-registered directive wins. Check Blade::getCustomDirectives() when a view renders the wrong branch.Gate::before registration (replaceable with your own for finer-grained super-admin logic), the config file for table names and cache TTL, and container bindings for any permission-resolver contract the package exposes. Prefer overriding via config/bindings over forking — the package's version number now moves with Laravel, so forks get expensive fast.Gate::before not returning an unexpected false (a before callback returning false is treated as a hard deny, not "no opinion"). That last one burns people.How can I help you explore Laravel packages today?