PHPackages                             enea/laravel-authorization - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. enea/laravel-authorization

ActivePackage[Authentication &amp; Authorization](/categories/authentication)

enea/laravel-authorization
==========================

Package to manage the permissions in a laravel application

v3.0(2y ago)31561MITPHPPHP ^8.1CI passing

Since Mar 25Pushed 5d ago1 watchersCompare

[ Source](https://github.com/vaened/laravel-authorization)[ Packagist](https://packagist.org/packages/enea/laravel-authorization)[ RSS](/packages/enea-laravel-authorization/feed)WikiDiscussions master Synced 2mo ago

READMEChangelog (2)Dependencies (6)Versions (14)Used By (0)

Laravel Authorization
=====================

[](#laravel-authorization)

[![Tests](https://github.com/vaened/laravel-authorization/actions/workflows/tests.yml/badge.svg)](https://github.com/vaened/laravel-authorization/actions/workflows/tests.yml)[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE)

Roles, permissions, explicit denials, and route middleware for Laravel applications.

Built on top of [PHP Sentinel](https://github.com/vaened/php-sentinel).

```
// Authorizations
$cashier         = $this->roles->create('cashier', 'Cashier');
$createDocuments = $this->permissions->create('documents.create', 'Create Documents');
$annulDocuments  = $this->permissions->create('documents.annul', 'Annul Documents');

// Assignment
$cashier->grant($createDocuments, $annulDocuments);
$user->grant($cashier);

// Evaluation
$user->actsAs('cashier');             // true
$user->can('documents.create');       // true
$user->can('documents.annul');        // true

// Deny overrides direct or inherited grants
$user->deny($annulDocuments);
$user->can('documents.annul');        // false
```

Installation
------------

[](#installation)

Laravel Authorization requires PHP 8.4 or higher and can be installed via Composer:

```
composer require vaened/laravel-authorization
```

Publish the package resources with the installer:

```
php artisan authorization:install
```

The installer can publish three resources:

- **Package configuration** — runtime settings for tables, cache, middleware, and Laravel Gate integration.
- **Authorization definitions** — the application's roles and permissions used by `authorization:sync`.
- **Database migrations** — the tables required to store roles, permissions, and their assignments.

Existing configuration files and migrations are skipped and never overwritten.

You can also publish each resource independently with its `vendor:publish` tag:

```
php artisan vendor:publish --tag=laravel-authorization-config
php artisan vendor:publish --tag=laravel-authorization-definitions
php artisan vendor:publish --tag=laravel-authorization-migrations
```

Then run your migrations:

```
php artisan migrate
```

Configuration
-------------

[](#configuration)

By default, your user model uses the package's direct authorization API through the `Authorizable` interface and `Authorizations` trait, and Sentinel integrates with Laravel's Gate using the `after` strategy. See [Advanced usage](#advanced-usage) when you prefer Laravel's native API.

### Using the direct model API

[](#using-the-direct-model-api)

Laravel Authorization does not require you to extend a package-specific user model.

Instead, the user model you want to make authorizable only needs to:

- implement [`Authorizable`](src/Authorizable.php)
- use [`Authorizations`](src/Authorizations.php)

```
use Illuminate\Foundation\Auth\User as Authenticatable;
use Vaened\Authorization\Authorizable;
use Vaened\Authorization\Authorizations;

class User extends Authenticatable implements Authorizable
{
    use Authorizations;
}
```

Once your user model uses the contract and trait above, it gains these capabilities:

MethodDescription`can(string ...$permissions): bool`Checks whether the user has at least one of the given permissions.`cannot(string ...$permissions): bool`Inverse of `can`.`actsAs(string ...$roles): bool`Checks whether the user has at least one of the given roles.`actsNotAs(string ...$roles): bool`Inverse of `actsAs`.`grant(Authorization ...$authorizations): void`Grants roles or permissions to the user.`deny(Permission ...$permissions): void`Explicitly denies permissions to the user.`revoke(Authorization ...$authorizations): void`Removes a previous grant or denial from the user.Authorization management
------------------------

[](#authorization-management)

Use PHP Sentinel's `RoleRegistry` and `PermissionRegistry` to manage the role and permission catalogs. Both registries expose the same API; their only difference is the authorization type they manage.

```
use Vaened\Sentinel\Registry\PermissionRegistry;
use Vaened\Sentinel\Registry\RoleRegistry;

final readonly class AuthorizationCatalog
{
    public function __construct(
        private RoleRegistry $roles,
        private PermissionRegistry $permissions,
    ) {
    }
}
```

MethodDescription`RoleRegistry` result`PermissionRegistry` result`create(string $code, string $name, ?string $description = null)`Creates a catalog entry.`Role``Permission``lookup(array $codes)`Retrieves the entries whose codes were requested.`Roles``Permissions``find(string $code)`Retrieves one entry by code, or `null` when it does not exist.`Role|null``Permission|null``update(int|string $id, string $name, ?string $description = null)`Updates an existing entry.`void``void``remove(int|string $id)`Removes an existing entry when it is no longer assigned.`void``void````
$cashier = $this->roles->create('cashier', 'Cashier');
$read = $this->permissions->create('documents.read', 'Read Documents');

$cashier->grant($read);

$permissions = $this->permissions->lookup(['documents.read', 'documents.update']);
$permission = $this->permissions->find('documents.read');
```

Middleware
----------

[](#middleware)

When Gate integration is enabled (the default), you can use Laravel's native `can` middleware for permission checks:

```
Route::middleware('can:posts.edit')->group(function () {
    // ...
});
```

Laravel's `can` middleware uses the Gate integration described in [Laravel Gate](#laravel-gate). It is available as long as `authorization.gate` is not `null`.

Laravel Authorization also registers two package middleware aliases. They are useful when you want to invoke Sentinel directly, including when Gate integration is disabled, and when you need to check roles.

- `authorization.permissions` allows the request only if the current authenticated user can perform at least one of the given permissions.
- `authorization.roles` allows the request only if the current authenticated user acts as at least one of the given roles.

```
Route::middleware('authorization.permissions:posts.edit')->group(function () {
    // ...
});

Route::middleware('authorization.roles:admin')->group(function () {
    // ...
});
```

If authorization fails, the middleware throws Laravel’s `AuthorizationException`.

You can rename these aliases by publishing and editing the `middlewares` array in [`config/authorization.php`](config/authorization.php).

Laravel Gate
------------

[](#laravel-gate)

Laravel Authorization can connect PHP Sentinel to Laravel's authorization Gate. This lets a compatible subject participate in Laravel's standard authorization features, including `Gate::allows`, the `can` route middleware, and Blade's `@can` directive.

Configure the `gate` option in [`config/authorization.php`](config/authorization.php):

```
'gate' => 'after', // 'after', 'before', or null
```

The default is `after`. Choose another strategy only when your application needs different precedence:

StrategyBehaviorUse it when`before`Sentinel evaluates the ability before Laravel's own Gates and Policies. Its result always decides the check.Sentinel is the authoritative authorization system for the application.`after`Laravel evaluates its own Gates and Policies first. Sentinel evaluates only when Laravel has no result.Recommended default; Sentinel acts as a fallback.`null`No Sentinel callback is registered in Laravel's Gate.The application should use Sentinel directly or manage Gate itself.Sentinel always resolves an ability to `true` or `false`: a subject either has the permission or it does not. It does not return Laravel's undecided `null` result. Consequently, `before` also denies abilities that Sentinel does not grant, while `after` preserves any explicit allow or denial already returned by Laravel.

Cache
-----

[](#cache)

Laravel Authorization caches each subject's authorization projection: its roles and the effective state of its permissions. The cache is updated or invalidated by the package when authorization assignments change.

You can configure it through the `cache` array in [`config/authorization.php`](config/authorization.php).

- `store` is the name of a store defined in your application's [`cache.stores`](https://laravel.com/docs/cache#configuration) configuration. Set it when authorization should use a dedicated Laravel cache store. When it is `null`, the package uses your application's default cache store.
- `prefix` namespaces the package's authorization cache entries so they remain isolated from other cached application data.
- `ttl` is the lifetime, in seconds, of a subject authorization projection. When it is `null` and the selected store supports cache tags, projections are kept permanently because the package can remove them explicitly. Stores without tag support use a twelve-hour TTL by default, so projections orphaned after a global invalidation eventually expire. Set an integer TTL to override it.

Database
--------

[](#database)

The package ships with five tables that back the entire authorization model:

TableWhat it stores`permissions`Atomic permissions (e.g. `users.read`, `posts.publish`). The catalog.`roles`Named groupings of permissions. The catalog.`role_permissions`Which permissions each role grants. Many-to-many between `roles` and `permissions`.`subject_roles`Which roles each subject carries. Polymorphic — works with any authorizable model.`subject_permissions`Direct grants and explicit denials on a subject. Polymorphic. A denial takes precedence over a direct or inherited grant.You can rename any of these tables by publishing and editing the `tables` array in [`config/authorization.php`](config/authorization.php). Each key corresponds to a table above.

Commands
--------

[](#commands)

### `authorization:install`

[](#authorizationinstall)

Publishes the package configuration, authorization definitions, and database migrations. It lets you select the resources interactively and skips any resource that already exists. Use the arrow keys to navigate, space to select, and Enter to confirm.

```
php artisan authorization:install
```

### `authorization:sync`

[](#authorizationsync)

Synchronizes the application's configured roles and permissions. See [Authorization synchronization](#authorization-synchronization) for details.

```
php artisan authorization:sync
```

### `authorization:cache:invalidate`

[](#authorizationcacheinvalidate)

Invalidates every authorization projection managed by the package:

```
php artisan authorization:cache:invalidate
```

Use it after authorization data is changed outside Laravel Authorization, such as through a direct database operation or an external integration.

Authorization synchronization
-----------------------------

[](#authorization-synchronization)

Authorization synchronization lets you define the application's roles and permissions in a configuration file and reconcile that definition with the authorization database through the [`authorization:sync`](#authorizationsync) command.

This feature is optional. Use it when you want to define application roles and permissions in code and synchronize them with the database. If your application manages authorization records through seeders, registries, or an administrative interface, you can omit this file and the synchronization command.

The definitions file is the source of truth for the permissions and roles that belong to the application. By default, it is:

```
config/authorizations.php

```

You can change the filename through `authorization.synchronization.config` in [`config/authorization.php`](config/authorization.php). Use the configuration key without the `.php` extension.

The file defines permissions by code and roles with their assigned permission codes:

```
return [
    'permissions' => [
        'users.read' => [
            'name' => 'Read users',
        ],
    ],
    'roles' => [
        'editor' => [
            'name'        => 'Editor',
            'permissions' => ['users.read'],
        ],
    ],
];
```

Each section can be disabled independently with `false` (or `null`):

```
return [
    'permissions' => [
        // Application permissions...
    ],
    'roles' => false,
];
```

In this example, permissions are synchronized while roles remain managed externally, such as through an administration panel. A section set to `false`, `null`, or omitted is not synchronized and is never pruned. An empty array is different: it enables synchronization and declares that no entries are expected for that section.

Run the [`authorization:sync`](#authorizationsync) command after changing the file. It creates missing entries, updates their metadata, and reconciles the permissions assigned to each role.

Use the optional `--prune` flag to remove roles and permissions that are no longer present in the file:

```
php artisan authorization:sync --prune
```

> Pruning is disabled by default and does not remove entries that are still in use.

Default models and repositories
-------------------------------

[](#default-models-and-repositories)

This package provides the Laravel-side infrastructure for [PHP Sentinel](https://github.com/vaened/php-sentinel):

- Eloquent repositories
- package configuration
- middleware integration
- service provider wiring

It also includes default models for roles and permissions. When using the direct model API, your application user is the authorization subject: implement the `Authorizable` contract and use the `Authorizations` trait.

Advanced usage
--------------

[](#advanced-usage)

The default setup is documented in [Using the direct model API](#using-the-direct-model-api) and [Laravel Gate](#laravel-gate). This section only covers the alternative integration where the model uses Laravel's native authorization API.

### Using Laravel's native authorization API

[](#using-laravels-native-authorization-api)

Use this mode when the application should use Laravel's own authorization API and does not need the package's direct model methods. Do not use the package's `Authorizable` interface or `Authorizations` trait. The model must implement Sentinel's `Subject` contract:

```
use Illuminate\Foundation\Auth\User as Authenticatable;
use Vaened\Sentinel\Identifier;
use Vaened\Sentinel\Subject;

class User extends Authenticatable implements Subject
{
    public function id(): int|string|Identifier
    {
        return $this->getKey();
    }
}
```

`Illuminate\\Foundation\\Auth\\User` already includes Laravel's native `Authorizable` trait. If your model extends Eloquent's base `Model` directly, use [`Illuminate\\Foundation\\Auth\\Access\\Authorizable`](https://github.com/laravel/framework/blob/13.x/src/Illuminate/Foundation/Auth/Access/Authorizable.php)on the model instead.

Use Laravel's own authorization implementation on the model. Keep `gate => 'after'` to let Sentinel serve as a fallback, use `before` only when Sentinel must take precedence, or use `null` when Laravel must operate without Sentinel Gate integration. See [Laravel Gate](#laravel-gate) for the exact precedence rules.

Without the package trait, manage assignments through the package facades:

```
use Vaened\Authorization\Facades\Denier;
use Vaened\Authorization\Facades\Granter;
use Vaened\Authorization\Facades\Revoker;

Granter::grant($user, $role);
Denier::deny($user, $permission);
Revoker::revoke($user, $permission);
```

> **Custom trait:** If you want to expose these operations as methods on your model, create a custom trait based on [`Authorizations`](src/Authorizations.php) and keep only the methods you need, such as `grant`, `deny`, and `revoke`. Omit `can` because Laravel provides that authorization API in this mode.

Do not combine the package's `Authorizations` trait with Laravel's `Authorizable` trait. Both define `can` and `cannot` with different contracts.

Errors
------

[](#errors)

Adapter-specific errors extend Sentinel’s base [`AuthorizationError`](https://github.com/vaened/php-sentinel/blob/master/src/Errors/AuthorizationError.php).

For example, if a subject used by the Laravel adapter does not extend Eloquent `Model`, the package throws:

- `UnsupportedSubject`

Middleware authorization failures continue to use Laravel’s own `AuthorizationException`.

Development
-----------

[](#development)

```
make composer-install
make test
```

Additional documentation
------------------------

[](#additional-documentation)

You can find more details in the source code as well as in the tests located in [`tests/`](tests).

The tests cover different usage scenarios and can serve as additional reference for understanding the library’s behavior.

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance65

Regular maintenance activity

Popularity15

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity79

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~211 days

Recently: every ~357 days

Total

12

Last Release

740d ago

Major Versions

V0.2.1 → V1.0.02018-04-15

V1.3.0 → V2.0.02022-07-11

V2.0.0 → v3.02024-08-05

PHP version history (4 changes)V0.0.1PHP ^7.1.3

V1.2.0PHP ^7.4

V1.3.0PHP ^7.4|^8.0

V2.0.0PHP ^8.1

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/15077850?v=4)[Enea Dhack](/maintainers/vaened)[@vaened](https://github.com/vaened)

---

Top Contributors

[![vaened](https://avatars.githubusercontent.com/u/15077850?v=4)](https://github.com/vaened "vaened (407 commits)")

---

Tags

authorizationsenealaravellaravel-authorizationpermissionsroleslaravelsecurityauthorizationaclpermissionenea

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/enea-laravel-authorization/health.svg)

```
[![Health](https://phpackages.com/badges/enea-laravel-authorization/health.svg)](https://phpackages.com/packages/enea-laravel-authorization)
```

###  Alternatives

[casbin/casbin

a powerful and efficient open-source access control library for php projects.

1.3k1.6M61](/packages/casbin-casbin)[laravel/nightwatch

The official Laravel Nightwatch package.

36911.6M45](/packages/laravel-nightwatch)[efficiently/authority-controller

AuthorityController is an PHP authorization library for Laravel 5 which restricts what resources a given user is allowed to access.

15333.3k](/packages/efficiently-authority-controller)[hosseinhezami/laravel-permission-manager

Advanced permission manager for Laravel.

353.3k](/packages/hosseinhezami-laravel-permission-manager)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
