cakephp / cakephp/authorization

Feature Request: Add allowUnauthorized() to AuthorizationComponent for parity with Authentication plugin

Open
#339 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
PHP
Stars
74
Forks
45
Avg merge
1d 17h
Merged PRs (30d)
1

Description

Description

Currently, the Authentication plugin provides a very convenient $this->Authentication->allowUnauthenticated(['action']) method to skip authentication checks for specific controller actions.

However, the Authorization plugin lacks a direct equivalent, forcing developers to manually call $this->Authorization->skipAuthorization() inside every public action or build custom logic in beforeFilter.

I propose adding an allowUnauthorized() method to AuthorizationComponent to bring API parity between both core plugins and streamline the handling of public/unauthorized actions.

Proposed Solution

We can introduce an internal tracker for unauthorized actions within the component and intercept the authorization checks before they hit the policies.

Here is a working implementation I am currently using by extending the base component:

<?php
declare(strict_types=1);

namespace Authorization\Controller\Component;

use Authorization\Policy\ResultInterface;
use Cake\Controller\Component;

class AuthorizationComponent extends Component 
{
    protected array $unauthorizedActions = [];

    /**
     * Allow specific actions to bypass authorization checks.
     *
     * @param array<string> $actions List of controller actions.
     * @return $this
     */
    public function allowUnauthorized(array $actions): static 
    {
        $this->unauthorizedActions = $actions;

        return $this;
    }

    /**
     * Overriding performCheck to automatically skip authorization for allowed actions
     */
    protected function performCheck(mixed $resource, ?string $action = null, string $method = 'can'): ResultInterface|bool 
    {
        $request = $this->getController()->getRequest();

        if ($action === null) {
             $action = $this->getDefaultAction($request);
        }

        if (in_array($action, ($this->unauthorizedActions)) {
            $this->skipAuthorization();
            return true;
        }

        return parent::performCheck($resource, $action, $method);
    }
}
Example Usage

This allows a much cleaner and intuitive setup in any controller's beforeFilter:

public function beforeFilter(\Cake\Event\EventInterface $event)
{
    parent::beforeFilter($event);
    $this->Authorization->allowUnauthorized([
        'login',
        'logout',
        'verify',
    ]);

    // Global authorization check for the rest of the actions
    if (!$this->Authorization->can($this)) {
        return $this->redirect('/');
    }
}
Why this should be added
  1. API Consistency: Alignment with how AuthenticationComponent::allowUnauthenticated() works.
  2. Cleaner Controllers: Avoids cluttering public actions with repetitive $this->Authorization->skipAuthorization() calls.
  3. Better DX: Centralizes access control rules in beforeFilter right next to authentication rules.

Additional Notes
  • Naming Conventions: I am completely open to suggestions regarding the names of the allowUnauthorized() method and the $unauthorizedActions property if the core team prefers a different naming convention (e.g., allowBypass(), skipActions(), etc.).
  • Pull Request: If the core team values this feature and approves the overall approach, I am more than happy to create and submit the Pull Request along with the necessary test cases.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with AuthorizationComponent and compare its existing authorization flow with AuthenticationComponent::allowUnauthenticated(). Decide how the proposed action tracker should interact with performCheck() and skipAuthorization(), then add the necessary component tests. Done means public actions can be configured to bypass authorization through a supported API without affecting checks for other actions.

Written by the indexing model from the issue text.

Assessment

Tech stack
php
Domain
authorization, backend
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.