Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Authorization Laravel Package

cakephp/authorization

CakePHP Authorization is a policy-based authorization plugin for CakePHP, offering middleware integration, request-level permission checks, and reusable policy classes. It helps centralize access rules and keep controllers clean, making role- and resource-based authorization easier to implement cons...

Deep Wiki
Context7

Getting Started

composer require cakephp/authorization

Register the middleware in src/Application.php, after AuthenticationMiddleware (the package reads the identity it attaches):

use Cake\Authorization\Middleware\AuthorizationMiddleware;
use Cake\Authorization\Middleware\RequestAuthorizationMiddleware;

public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
    $middlewareQueue
        ->add(new ErrorHandlerMiddleware())
        ->add(new AuthenticationMiddleware($this))
        ->add(new AuthorizationMiddleware())        // service + policy resolver
        ->add(new RequestAuthorizationMiddleware()); // request-level policy checks
    return $middlewareQueue;
}

Look here first:

  • Cake\Authorization\AuthorizationService — the can() / authorize() / applyScope() API you'll call from controllers.
  • Cake\Authorization\PolicyResolver — how entity/table/request classes map to Policy classes (App\Policy\{EntityClass}Policy).
  • Cake\Authorization\Policy\BeforePolicyInterface — the escape hatch for "superuser bypasses everything".

First use case — gate a controller action on an entity:

// src/Policy/ArticlePolicy.php
class ArticlePolicy
{
    public function canEdit(IdentityInterface $user, Article $article): bool
    {
        return $user->getIdentifier() === $article->user_id;
    }
}

// Controller
public function edit($id)
{
    $article = $this->Articles->get($id);
    $this->Authorization->authorize($article, 'edit'); // throws ForbiddenException
    // ...
}

Implementation Patterns

Policy method naming convention. can{Action} for object-level checks. The action name is case-insensitive (edit → canEdit). Return bool, AuthorizationResult, or null (undecided). Use AuthorizationResult::allowIf() when checks are expensive or composed.

Table policies + scopes for indexes. The dominant pattern is scopeIndex on the table policy, applied via the service rather than a can* method:

// src/Policy/ArticlesTablePolicy.php
public function scopeIndex(IdentityInterface $user, SelectQuery $query): SelectQuery
{
    return $user->get('is_admin')
        ? $query
        : $query->where(['Articles.user_id' => $user->getIdentifier()]);
}

// Controller index()
$query = $this->Authorization->applyScope($this->Articles->find());

applyScope() requires the scope method to exist on the resolved policy, so put scopeIndex on ArticlesTablePolicy and canEdit/canDelete on ArticlePolicy (entity).

Request policies for route access. RequestPolicy short-circuits before your controller runs:

class RequestPolicy
{
    public function canAccess(IdentityInterface $user, ServerRequest $request): bool
    {
        return $user->get('is_active');
    }
    public function canBypass(IdentityInterface $user, ServerRequest $request): bool
    {
        return $user->get('is_admin');
    }
}

canBypass is checked first and, if true, skips all downstream authorization in that request — great for admin back offices, dangerous if broad.

Non-throwing checks for UI. Use the service directly so views can hide buttons without exceptions:

$result = $this->Authorization->can($article, 'edit');
if ($result->getStatus()) { /* render edit link */ }

Identity decorators / custom service. Bind AuthorizationServiceInterface and PolicyResolverInterface in the container to swap in multi-tenant policy lookup or an identity that carries tenant scope:

// src/Application.php
$container->add(AuthorizationServiceInterface::class, TenantAuthorizationService::class);

Testing. PolicyTestTrait lets you assert policy methods directly without spinning up a request:

use Cake\Authorization\TestSuite\PolicyTestTrait;
$result = $this->assertPolicyAllows('edit', $article, $editor);

Gotchas and Tips

  • Despite the "PSR7 middleware" description, this is not framework-agnostic. It is coupled to Cake\Http\ServerRequest, IdentityInterface, and Cake conventions. Do not expect it to drop into Slim/Laminas; for those use mezzio-authorization or psr7-session middleware.
  • Middleware ordering is the #1 failure. AuthorizationMiddleware before AuthenticationMiddleware → MissingIdentityException on every request. RequestAuthorizationMiddleware must run at routing scope — put it in Application::routes() via $routes->registerMiddleware(), not only in middleware(), or it never fires for route-level checks.
  • Missing scopeIndex doesn't fail closed. applyScope() throws if the method is absent, but a policy that returns the unfiltered query leaks rows — audit scopes like you'd audit SQL.
  • can* returning null/no method = denied. There is no silent allow. Verify your method name casing matches the action, and remember canIndex on entity policy is not used for controller indexes—use scopeIndex on the table policy.
  • skipAuthorization() is a footgun. It disables both middleware and controller checks for the rest of the request. Prefer canBypass in a RequestPolicy so the exception is centralized and auditable.
  • Forbidden vs. missing. MissingIdentityException means the identity middleware didn't run or the user isn't logged in; ForbiddenException means a policy denied. Map them to 401 vs 403 in your error handler — they are not interchangeable.
  • Version alignment. 2.x targets CakePHP 5 / PHP 8.1+. 1.x is CakePHP 4. Pin the major to your framework; the resolver signature changed between them.
  • Debugging. There is no built-in logger. Wire a try/catch around authorize() in a base controller, or decorate PolicyResolverInterface to log (identity id, policy class, method, result) — invaluable when a policy appears both to run and to be ignored.
  • Extension points worth knowing: PolicyResolverInterface (custom class-to-policy mapping), BeforePolicyInterface (root bypass), AuthorizationResult/ResultInterface (composable decisions), and the AuthorizationMiddleware identityAttribute option if your identity lives under a non-default request attribute.
  • Stale identity. The middleware captures identity once. If you mutate the logged-in user's roles mid-request (e.g., impersonation), re-resolve and reassign before the next can() call or checks will use the old object.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource