PHPackages                             deefour/authorizer - 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. deefour/authorizer

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

deefour/authorizer
==================

Simple Authorization via PHP Classes

2.2.0(9y ago)483.3k↓100%5MITPHPPHP &gt;=5.6.0

Since Nov 13Pushed 9y ago6 watchersCompare

[ Source](https://github.com/deefour/authorizer)[ Packagist](https://packagist.org/packages/deefour/authorizer)[ Docs](https://github.com/deefour/authorizer)[ RSS](/packages/deefour-authorizer/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (3)Versions (24)Used By (0)

Authorizer
==========

[](#authorizer)

[![Build Status](https://camo.githubusercontent.com/432435531cd1116a9c1c4b76ee8e5fbdf4ecb611cbbf99e613e83db4e1dc2c73/68747470733a2f2f7472617669732d63692e6f72672f646565666f75722f617574686f72697a65722e737667)](https://travis-ci.org/deefour/authorizer)[![Total Downloads](https://camo.githubusercontent.com/4fbf7b9e53dd4584c560956fb8867858676d76890ad610a1cd0f3c1ac85ac8f3/68747470733a2f2f706f7365722e707567782e6f72672f646565666f75722f617574686f72697a65722f642f746f74616c2e737667)](https://packagist.org/packages/deefour/authorizer)[![Latest Stable Version](https://camo.githubusercontent.com/e2f348320267a66e0044d5b2bfe48b0c8035d5ad6836d988f718c3094a67747c/68747470733a2f2f706f7365722e707567782e6f72672f646565666f75722f617574686f72697a65722f762f737461626c652e737667)](https://packagist.org/packages/deefour/authorizer)[![License](https://camo.githubusercontent.com/43fe9b34cc7e61a04e59e7c788b2df9c14d197a65035820dce1904f3dfba49a1/68747470733a2f2f706f7365722e707567782e6f72672f646565666f75722f617574686f72697a65722f6c6963656e73652e737667)](https://packagist.org/packages/deefour/authorizer)

Simple Authorization via PHP Classes. Inspired by [elabs/**pundit**](https://github.com/elabs/pundit).

Getting Started
---------------

[](#getting-started)

Run the following to add Authorizer to your project's `composer.json`. See [Packagist](https://packagist.org/packages/deefour/authorizer) for specific versions.

```
composer require deefour/authorizer
```

**`>=PHP5.6.0` is required.**

Policies
--------

[](#policies)

At the core of Authorizer is the notion of policy classes. Policies accept a `$user` and `$record` during instantiation. Public methods (actions) contain logic to check if the `$user` can perform the action on the `$record`. Here is an example of a policy that authorizes users to create and edit article objects.

```
class ArticlePolicy
{
    protected $user;

    protected $record;

    public function __construct($user, $record)
    {
        $this->user = $user;
        $this->record = $record;
    }

    public function create()
    {
        return $this->user->exists;
    }

    public function edit()
    {
        return $this->record->exists && $this->record->author->is($user);
    }
}
```

This policy allows any existing user to create a new article, and existing articles to be modified only by their author. Here are examples of how you might interact directly with this policy.

```
(new ArticlePolicy($user, new Article))->create(); // => true
(new ArticlePolicy($user, Article::class))->create(); // => true
(new ArticlePolicy($user, new Article))->edit(); // => false
(new ArticlePolicy($user, $user->articles->first()))->edit(); // => true
```

### Mass Assignment Protection

[](#mass-assignment-protection)

A `permittedAttributes` method on a policy provides a whitelist of attributes for a request by a user when performing an action.

```
class ArticlePolicy
{
    public function permittedAttributes()
    {
        $attributes = [ 'title', 'body', ];

        // prevent the author and slug from being modified after the article
        // has been persisted to the database.
        if ( ! $this->record->exists) {
            return array_merge($attributes, [ 'user_id', 'slug', ]);
        }

        return $attributes;
    }
}
```

Action-specific methods can also be provided by in the format `permittedAttributesFor{Action}`.

```
class ArticlePolicy
{
    public function permittedAttributesForCreate()
    {
        return [ 'title', 'body', 'user_id', 'slug ];
    }

    public functoin permittedAttributesForEdit()
    {
        return [ 'title', 'body' ];
    }
}
```

Scopes
------

[](#scopes)

Authorizer also provides support for retrieving a resultset restricted based on a user's ability through scopes. A scope object receives a `$user` and base `$scope` during instantiation. It is expected to implement a `resolve()` method with logic to refine the `$scope` and typically return an iterable collection of objects the current user is able to access. For example

```
class ArticleScope
{
    protected $user;

    protected $scope;

    public __construct($user, $scope)
    {
        $this->user = $user;
        $this->scope = $scope;
    }

    public function resolve()
    {
        if ($this->user->isAdmin()) {
            return $this->scope->all();
        }

        return $this->scope->where('published', true)->get();
    }
}
```

This scope retrieves all articles if the current user is an administrator, and only published articles for other users.

```
$user = User::first();
$query = Article::newQuery();

(new ArticleScope($user, $query))->resolve(); //=> iterable list of Article objects
```

The Authorizer Object
---------------------

[](#the-authorizer-object)

Creating and working with policy and scope classes directly is fine, but there are easier ways to authorize user activity. The first is the `Deefour\Authorizer\Authorizer` class.

### Resolving Policies

[](#resolving-policies)

A policy can be instantiated and returned based on a `$user` and `$record`.

```
(new Authorizer)->policy(new User, Article::class); //=> ArticlePolicy
```

The policy resolution just appends `'Policy'` to the end of the `$record`'s class name by default. This can be customized by provided a static `policyClass` method on the `$record` class. For example, if the policy for `Article` is at `Policies\ArticlePolicy`, create a method like this:

```
class Article
{
    static public function policyClass()
    {
        return \Policies\ArticlePolicy::class;
    }
}
```

> It's recommended that your `$record` objects extend a single class that implements a `policyClass` method that will work for most/all of your record classes instead of manually specifying FQN's on every record.

### Resloving Scopes

[](#resloving-scopes)

A scope can be instantiated and returned based on a `$user` and base `$scope`. Instead of returning a scope class, `Authorizer` will call `resolve()` on the scope class for you, returning the resultset.

```
(new Authorizer)->scope(new User, new Article); //=> a scoped resultset
```

Similar to policy resolution, the scope resolution just appends `'Scope'` to the end of the `$scope` object by default. This can be customized by provided a static `scopeClass` method on the `$record` class.

```
class Article
{
    static public function scopeClass()
    {
        return \Policies\ArticleScope::class;
    }
}
```

It's important to note that many times you will pass a partially built query object to the `scope()` method as the `$record` instead of an instance of a record that actually resolves to a scope class. For example, a more realistic example of the one above might look like this:

```
(new Authorizer)->scope(new User, Article::where('promoted', true)); //=> ArticleScope
```

The second argument above will return an instance of `Illuminate\Database\Eloquent\Builder` instead of an instance of `Article`. Scope resolution will fail without a bit more help. The resolver must be told how to determine the actual record to resolve the scope from. This is done through a closure passed as an optional third argument which will be passed the `$scope` the authorizer receives.

```
(new Authorizer)->scope(
    new User,
    Article::where('promoted', true),
    function ($scope) {
        return $scope->getModel();
    }
); //=> a scoped resultset
```

### Strict Resolution

[](#strict-resolution)

If a policy or scope cannot be found, `null` will be returned. If you need to stop execution, call `policyOrFail()` or `scopeOrFail()` instead of simply `policy()` or `scope()`.

```
(new Authorizer)->policyOrFail(new User, new Blog); //=> throws Deefour\Authorizer\Exception\NotDefinedException
```

### Authorization

[](#authorization)

The authorizer also provides an `authorize` method that receives a `$user`, `$record`, and `$action`. An exception will be thrown if anything but `true` is returned from the resolved policy's action method.

```
(new Authorizer)->policyOrFail(new User, new Article, 'edit'); //=> throws Deefour\Authorizer\Exception\NotAuthorizedException
```

### Failure Reasons

[](#failure-reasons)

Authorizer considers any value other than `true` returned from a policy action a failure. If a string is returned it will be passed through as the message on the thrown `NotAuthorizedException`. This message can be used to inform a user exactly why their attempt to perform action was denied.

```
class ArticlePolicy
{
    public function edit()
    {
        if ($this->record->user->is($this->user)) {
            return true;
        }

        return 'You are not the owner of this article.';
    }
}
```

```
try {
    (new Authorizer)->authorize(new User, new Article, 'edit');
} catch (NotAuthorizedException $e) {
    echo $e->getMessage(); //=> 'You are not the owner of this article.'
}
```

### Permitted Attributes

[](#permitted-attributes)

Authorizer can fetch a whitelist of attribute names permitted for mass assignment for a particular action.

```
(new Authorizer)->permittedAttributes(new User, new Article); //=> ArticlePolicy::permittedAttributes()
(new Authorizer)->permittedAttributes(new User, new Article, 'store'); //=> ArticlePolicy::permittedAttributesForStore()
```

### Closed System

[](#closed-system)

Many apps only allow users to perform actions while authenticated. Instead of verifying on every policy action that the current user is logged in, you can create a base policy all others extend.

```
abstract class Policy
{
    public function __construct($user, $record)
    {
        if (is_null($user) or ! $user->exists) {
            throw new NotAuthorizedException($record, $this, 'initalization', 'You must be logged in!');
        }

        parent::__construct($user, $record);
    }
}
```

Making Classes Aware of Authorization
-------------------------------------

[](#making-classes-aware-of-authorization)

In addition to the `Authorizer` class, a `Deefour\Authorizer\ProvidesAuthorization` trait is also provided to make authorizing user activity easier.

### Preparing for Authorization

[](#preparing-for-authorization)

This trait can be used in any class provided it overrides the following three `protected` methods on the implementing class:

#### `authorizerUser()`

[](#authorizeruser)

This should return the user object to authorize. It can be useful to return a new/fresh/empty user object if no logged in user is present.

#### `authorizerAction()`

[](#authorizeraction)

This should return the name of the action on the policy to be called. Often this is based on the controller method handling the current request.

#### `authorizerAttributes()`

[](#authorizerattributes)

This should return an array of input data for the request. This only needs to be overridden if you are taking advantage of the mass assignment protection.

### Usage

[](#usage)

#### Retrieving Policies

[](#retrieving-policies)

With this trait included, a policy can be retrieved from within the controller. The `$user` needed for the policy instantiation is derived from the `authorizerUser()` method override.

```
$this->policy(new Article); //=> ArticlePolicy
```

#### Retrieving Scopes

[](#retrieving-scopes)

Scoping can be done with similar simplicity. Similar to the `Authorizer` class, this will call `resolve()` on the scope for you, returning the resultset. A closure is provided below returning the `$record` which the scope class should be resolved from based on the passed base `$scope`.

```
$this->scope(
  Article::newQuery(),
  function($scope) {
      return $scope->getModel();
  }
); //=> a scoped resultset
```

Like policy resolution, the `$user` needed for the policy instantiation is derived from the `authorizerUser()` method override.

#### Authorization Checks

[](#authorization-checks)

A failing authorization check will throw an instance of `Deefour\Authorizer\Exception\NotAuthorizedException`. This can short-circuit method execution with a single line of code.

```
public function edit(Article $article)
{
    $this->authorize($article); //=> NotAuthorizedException will be thrown on failure

    echo "You can edit this article!"
}
```

Similar to policies, the `$user` and `$action` needed for the scope instantiation are derived from the `authorizerUser()` and `authorizerAction()` method overrides. An action can be passed as a second argument to call a specific method on the policy instead of the one `authorizerAction()` will return.

```
$this->authorize($article, 'modify');
```

#### Mass Assignment

[](#mass-assignment)

Model attributes can be safely mass assigned too. Calling `permittedAttributes()` will pull a whitelist of attributes from the request info returned from the `authorizerAttributes()` method. A policy is instantiated for the `$record` behind the scenes, again with the `$user` and `$action` needed being derived from the `authorizerUser()` and `authorizerAction()` method overrides.

```
public function update(Article $article)
{
  $article->forceFill($this->permittedAttributes(new Article))->save();
}
```

A second argument can be provided to `permittedAttributes()` to call a specific variant of the method on the policy if available.

### Authorization Within Laravel

[](#authorization-within-laravel)

Integrating this library into a Laravel application is very straightforward.

#### Implementing the Trait Method Overrides

[](#implementing-the-trait-method-overrides)

Within a Laravel application, an implementation satisfying the above overrides might look like this:

```
use App\User;
use Auth;
use Deefour\Authorizer\ProvidesAuthorization;
use Illuminate\Routing\Controller as BaseController;
use Request;
use Route;

class Controller extends BaseController
{
    use ProvidesAuthorization;

    protected function authorizerAction()
    {
        $action = Route::getCurrentRoute()->getActionName();

        return substr($action, strpos($action, '@') + 1);
    }

    protected function authorizerUser()
    {
        return Auth::user() ?: new User;
    }

    protected function authorizerAttributes()
    {
        return Request::all();
    }
}
```

#### Gracefully Handling Unauthorized Exceptions

[](#gracefully-handling-unauthorized-exceptions)

When a call to `authorize()` fails, a `Deefour\Authorizer\NotAuthorizedException` exception is thrown. Your Laravel app's `App\Exceptions\Handler` could be modified to support this exception.

1. Add `Deefour\Authorizer\Exception\NotAuthorizedException:class` to the `$dontReport` list.
2. Import `Deefour\Authorizer\Exception\NotAuthorizedException` at the top of the file.
3. Make your `prepareException()` method look like this:

    ```
    ```

protected function prepareException(Exception $e) { if ($e instanceof NotAuthorizedException) { return new HttpException(403, $e-&gt;getMessage()); }

```
    return parent::prepareException($e);
}
```

```

#### Ensuring Policies Are Used

[](#ensuring-policies-are-used)

An middleware can be provided on a controller's constructor as a closure to prevent actions missing authorization checks from being wide open by default.

```
public function __construct()
{
    $this->middleware(function ($request, $next) {
      $response = $next($request);

      $this->verifyAuthorized();

      return $response;
    });
}
```

This will throw a `Deefour\Authorizer\Exceptions\AuthorizationNotPerformedException` exception if the controller action is run without a call to `authorize()`.

There is a `verifyScoped` method to ensure a scope is used that will throw a `Deefour\Authorizer\Exceptions\ScopingNotPerformedException` if the controller action is run without a call to `scope()`.

On occasion, bypassing this blanket authorization or scoping requirement may be necessary. Exceptions will not be thrown if `skipAuthorization()` or `skipScoping()` are called before the verification occurs.

### Helping Form Requests

[](#helping-form-requests)

Laravel's `Illuminate\Foundation\Http\FormRequest` class has an `authorize()` method. Integrating policies into form request objects is easy. An added benefit is the validation rules can be based on authorization too:

```
namespace App\Http\Requests;

use Deefour\Authorizer\ProvidesAuthorization;
use Illuminate\Foundation\Http\FormRequest;

class CreateArticleRequest extends FormRequest
{
    use ProvidesAuthorization;

    public function authorize()
    {
        return $this->authorize(new Article);
    }

    public function rules()
    {
        $rules = [
            'title' => 'required'
        ];

        if ( ! $this->policy->createWithoutApproval()) {
            $rules['approval_from'] => 'required';
        }

        return $rules;
    }

    protected authorizerUser()
    {
        return $this->user();
    }

    protected authorizerAttributes()
    {
        return $this->all();
    }

    protected authorizerAction()
    {
        return $this->has('id') ? 'create' : 'edit';
    }
}
```

Contribute
----------

[](#contribute)

- Issue Tracker:
- Source Code:

Changelog
---------

[](#changelog)

#### 2.2.0 - February 12, 2017

[](#220---february-12-2017)

- The `modelName()` method checked on a class to resolve a different policies and scopes against a different model has been changed to `modelClass()`.

#### 2.1.1 - February 8, 2017

[](#211---february-8-2017)

- Bugfixes for scope resolution, thanks to [@gmedeiros](https://github.com/gmedeiros).

#### 2.1.0 - September 14, 2016

[](#210---september-14-2016)

- Made `permittedAttributes()` available in the `Authorizer` class.
- Docblocks throughout.

#### 2.0.0 - September 13, 2016

[](#200---september-13-2016)

- Complete rewrite.
- Much of the API is the same, but many interfaces and base classes have been removed for simplicity.
- Laravel-specific global functions, facade, and service provider have been removed.
- Class resolution has been simplified (no more dependence on [deefour/producer](https://github.com/deefour/producer)).

#### 1.1.0 - January 14, 2016

[](#110---january-14-2016)

- The `Authorizer` now does a strict type check. A `NotAuthorizedException` unless `true` is returned. Other 'truthy' values will fail authorization.
- A string returned from a policy will now be set as the 'reason' for the authorization failure.

#### 1.0.0 - October 7, 2015

[](#100---october-7-2015)

- Release 1.0.0.
- New `skipAuthorization()` and `skipScoping()` methods have been added. to bypass the exception throwing of the verification API.

#### 0.6.0 - August 8, 2015

[](#060---august-8-2015)

- Large rewrite of the policy and scope resolver, now using [`deefour/producer`](https://github.com/deefour/producer).
- The `policyNamespace()`, `policyClass()`, `scopeNamespace()` and `scopeClass()` methods have all been removed in favor of a single `resolve()` method now, used by the `deefour/producer` resolver.
- Policies now **require** an `Authorizee` be passed to the constructor.

#### 0.5.2 - July 31, 2015

[](#052---july-31-2015)

- Throw `403` instead of `401` when unauthorized.

#### 0.5.1 - June 5, 2015

[](#051---june-5-2015)

- Now following PSR-2.

#### 0.5.0 - June 2, 2015

[](#050---june-2-2015)

- All static methods are now public instance methods.
- Changed `currentUser()` to `user()` for simplicity and compatibility with Laravel.
- Code cleaning.

#### 0.4.0 - March 25, 2015

[](#040---march-25-2015)

- New `ResolvesAuthorizable` interface. This can be used on a class such as the decorators in [`deefour/presenter`](https://github.com/deefour/presenter) to map an authorization attempt back to the underlying model, since the presenter itself is not implementing the `Authorizable` interface.
- Now requires `symfony/http-kernel` to throw a full HTTP exception when authorization fails.
- Code formatting improved.

#### 0.3.0 - March 19, 2015

[](#030---march-19-2015)

- Adding much improved support for policy scopes.
- Remove `helpers.php` from Composer autoload. Developers should be able to choose whether these functions are included.
- Cleaned up docblocks.

#### 0.2.0 - February 4, 2015

[](#020---february-4-2015)

- Adding `Authorizee` contract to be attached to a `User` model for easy lookup through service containers.
- Class Reorganization.
- Fixes for the Laravel service provider.

#### 0.1.0 - November 13, 2014

[](#010---november-13-2014)

- Initial release independent of [deefour/Aide](https://github.com/deefour/aide).

License
-------

[](#license)

Copyright (c) 2016 [Jason Daly](http://www.deefour.me) ([deefour](https://github.com/deefour)). Released under the [MIT License](http://deefour.mit-license.org/). 0Looking

###  Health Score

37

—

LowBetter than 82% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity30

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity68

Established project with proven stability

 Bus Factor1

Top contributor holds 98.6% 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 ~39 days

Total

22

Last Release

3372d ago

Major Versions

0.5.3 → 1.0.02015-10-07

1.3.0 → 2.0.02016-09-13

PHP version history (2 changes)0.1.0PHP &gt;=5.5.0

2.0.0PHP &gt;=5.6.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/0a2bddbe9f87813e53e82c1799b460513ede9f96a1d85ad7c186c0692a6f0762?d=identicon)[deefour](/maintainers/deefour)

---

Top Contributors

[![deefour](https://avatars.githubusercontent.com/u/14762?v=4)](https://github.com/deefour "deefour (140 commits)")[![gmedeiros](https://avatars.githubusercontent.com/u/3370868?v=4)](https://github.com/gmedeiros "gmedeiros (2 commits)")

---

Tags

authauthorizationguardmass-assignmentphppolicylaravelauthorizationscopepoliciesPolicydeefourauthorizer

###  Code Quality

Code StylePHP CS Fixer

### Embed Badge

![Health badge](/badges/deefour-authorizer/health.svg)

```
[![Health](https://phpackages.com/badges/deefour-authorizer/health.svg)](https://phpackages.com/packages/deefour-authorizer)
```

###  Alternatives

[pktharindu/nova-permissions

Laravel Nova Grouped Permissions (ACL)

136387.1k](/packages/pktharindu-nova-permissions)[silvanite/novatoolpermissions

Laravel Nova Permissions (Roles and Permission based Access Control (ACL))

100256.7k2](/packages/silvanite-novatoolpermissions)[spatie/laravel-authorize

A middleware to check authorization

20125.8k1](/packages/spatie-laravel-authorize)[hasinhayder/tyro

Tyro - The ultimate Authentication, Authorization, and Role &amp; Privilege Management solution for Laravel 12 &amp; 13

6712.1k2](/packages/hasinhayder-tyro)

PHPackages © 2026

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