phalcon/cphalcon · error · Phalcon\Auth\Exceptions\AccessDenied

Access denied for {type} '{name}'

Error message

Access denied for {type} '{name}'

What it means

The Auth dispatcher listener enforces access via an access gate (e.g. Phalcon\Auth\Access\Acl). When the gate denies an action, the listener first tries to recover by forwarding to a redirect target; only if no forward handler is available or the access policy exposes no redirectTo() does it throw AccessDenied labelled with the action type ('task', 'action', 'route') and the action name. It is the terminal signal that a request was refused and no graceful redirect was configured.

Source

Thrown at phalcon/Auth/AbstractAuthDispatcherListener.zep:80

        let access = this->manager->getAccess();
        if (access === null) {
            return true;
        }

        if (access->isAllowed(this->manager->guard(), actionName, context)) {
            return true;
        }

        if (forwardHandler !== null) {
            let target = access->redirectTo();
            if (target !== null) {
                {forwardHandler}(target);

                return false;
            }
        }

        throw new AccessDenied(this->getActionType(), actionName);
    }

    /**
     * Returns the kind label used by AccessDenied (e.g. 'task', 'action',
     * 'route').
     */
    abstract protected function getActionType() -> string;
}

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Grant access: add the matching `$acl->allow($role, $component, $action)` rule or assign the user the required role
  2. Configure graceful denial: set redirectTo() on the access policy and pass a forward handler to enforce() so refusals forward (e.g. to login) instead of throwing
  3. Whitelist genuinely public actions in the access policy's exceptActions

Example fix

// before: denial throws
$this->enforce('index', $context, null);
// after: denial forwards to login
$this->enforce('index', $context, function (array $target) {
    $this->dispatcher->forward(['controller' => 'session', 'action' => 'login']);
});
// plus in the access policy: protected function redirectTo(): ?array { return ['controller' => 'session', 'action' => 'login']; }
Defensive patterns

Strategy: try-catch

Validate before calling

if (!$acl->isAllowed($user->getRoleName(), $component, $actionName)) {
    $response->redirect('/login')->send();
    return;
}

Try / catch

try {
    $dispatcher->dispatch();
} catch (\Phalcon\Auth\Exceptions\AccessDenied $e) {
    $logger->notice('Access denied: ' . $e->getMessage());
    $response->setStatusCode(403)->setContent('Forbidden')->send();
}

Prevention

When it happens

Trigger: `$listener->enforce($actionName, $context, $forwardHandler)` (or the dispatcher event that calls it) where the gate's isAllowed() returns false and either forwardHandler is null or the access object's redirectTo() returns null.

Common situations: Wiring the new Phalcon Auth component without configuring a redirect for denied users; ACL rules missing an allow entry for the user's role; forgetting to add a public action to the access policy's exceptActions.

Understand the failure class

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/a21f50f4d109ba3e. Report an issue: GitHub.