Search by

laravarc / authorizer

RBAC engine for Laravel — Gate::before abilities, roles, and tenant-scoped authorization. Usable with or without laravarc/core.

Maintainers

Package info

github.com/laravarc/authorizer

pkg:composer/laravarc/authorizer

Transparency log

Statistics

Installs: 2

Dependents: 1

Suggesters: 1

Stars: 1

Open Issues: 0

v1.0.0 2026-09-05 16:59 UTC

This package is auto-updated.

Last update: 2026-09-05 17:18:46 UTC


README

RBAC for Laravel — roles, abilities, and Gate::before() checks.

Works in any Laravel 10–13 application, with or without laravarc/core.

Design

  • Policy = business rule — policy classes stay plain; they never call Authorizer.
  • Authorizer = RBAC — ability checks run in Gate::before() before policy methods.
  • Source of truth is code — abilities are discovered from policy classes (or Core metadata), never created ad-hoc via a public Ability::create() API.
  • Tenant-readytenant_id on roles is a plain nullable id (no foreign key). Swap TenantResolver for multi-tenant apps.

Installation

composer require laravarc/authorizer
php artisan vendor:publish --tag=authorizer-config
php artisan migrate
php artisan laravarc:authorizer install
php artisan laravarc:authorizer cache
php artisan laravarc:authorizer sync

Add the trait to your user model:

use Laravarc\Authorizer\Concerns\HasAuthorizerAbilities;

class User extends Authenticatable
{
    use HasAuthorizerAbilities;
}

Route middleware

Alias Purpose
laravarc.authorize.super Require an authenticated user with an Authorizer super role (isSuper())
Route::middleware(['auth:sanctum', 'laravarc.authorize.super'])->group(function (): void {
    // privileged routes
});

When using laravarc/core, ability-based route checks use Core's laravarc.authorize middleware (same laravarc.authorize* family).

How authorization works

Gate::authorize('delete', $customer)
  → Gate::before (Authorizer)
       is_super?     → true  (bypass, policy skipped)
       known + deny? → false (403, policy skipped)
       known + allow → null  (continue)
       unknown?      → null  (continue)
  → CustomerPolicy::delete()   // business rule only

Fluent API

use Laravarc\Authorizer\Facades\Authorization;
use Laravarc\Authorizer\Facades\Role;
use App\Policies\CustomerPolicy;

Role::create('Accounting')->tenant($companyId)
    ->grant(CustomerPolicy::class)->only(['view', 'update']);

Role::create('Admin')->grant(CustomerPolicy::class); // all abilities

Authorization::role('Accounting')->grant(CustomerPolicy::class)->except(['delete']);
Authorization::user($user)->assignRole('Accounting');
Authorization::user($user)->allow(CustomerPolicy::class)->only(['export']);

Grant expansion

grant(Policy::class) stores expanded rows in larc_role_abilities (one per ability), not a live policy.* rule.

When laravarc:authorizer sync later discovers a new method on that policy, existing roles that previously granted the policy do not automatically receive the new ability. Re-grant the policy (or grant the new method) after sync.

Commands

Command Alias Purpose
laravarc:authorizer cache larc:authorizer cache Build ability index (PSR-4 policy scan)
laravarc:authorizer cache --clear same Clear cached index
laravarc:authorizer sync larc:authorizer sync Sync abilities to the database
laravarc:authorizer sync --dry-run same Preview only
laravarc:authorizer sync --auto-delete-missing same Delete missing abilities without prompts
laravarc:authorizer install larc:authorizer install Seed the system super role (is_super + is_system)

Multi-tenant

use Laravarc\Authorizer\Contracts\TenantResolver;

$this->app->singleton(TenantResolver::class, CompanyTenantResolver::class);

null from current() means global (single-tenant) roles and leaves hasAbility() on the union-all path. When current() returns a non-null id, hasAbility() only counts role grants for roles with that tenant_id (is_super still bypasses; NULL-tenant non-super roles do not match). Role name uniqueness is enforced in the service layer (SQL UNIQUE alone is unsafe with NULL tenant_id).

Core integration (optional)

// config/laravarc.php
'extensions' => [
    \Laravarc\Core\Authorizer\AuthorizerCoreExtension::class,
],

Core rebinds AbilityRegistry to MetadataAbilityRegistry. Authorizer never imports Core.

License

MIT — see LICENSE.