yiisoft/yii2 · error · ForbiddenHttpException

You are not allowed to perform this action.

Error message

You are not allowed to perform this action.

What it means

yii\filters\AccessControl::denyAccess() runs when no access rule matched the request with allow=true. If the current user is a guest it calls loginRequired() (redirect to login), but for an authenticated user - or when the User component is detached ($user === false) - it throws ForbiddenHttpException with 'You are not allowed to perform this action.', which Yii renders as HTTP 403.

Source

Thrown at framework/filters/AccessControl.php:159

            $this->denyAccess($user);
        }

        return false;
    }

    /**
     * Denies the access of the user.
     * The default implementation will redirect the user to the login page if he is a guest;
     * if the user is already logged, a 403 HTTP exception will be thrown.
     * @param User|false $user the current user or boolean `false` in case of detached User component
     * @throws ForbiddenHttpException if the user is already logged in or in case of detached User component.
     */
    protected function denyAccess($user)
    {
        if ($user !== false && $user->getIsGuest()) {
            $user->loginRequired();
        } else {
            throw new ForbiddenHttpException(Yii::t('yii', 'You are not allowed to perform this action.'));
        }
    }
}

View on GitHub (pinned to 66f00d18a2)

Solutions

  1. Adjust the rules so legitimate users match: add the user's role to 'roles', fix the 'verbs'/'ips'/'matchCallback' condition.
  2. Assign the required RBAC permission to the role/user (auth manager assignment migration).
  3. For stateless APIs, configure AccessControl with 'user' => false knowingly and return 401 semantics yourself, or use yii\filters\auth\HttpHeaderAuth instead.
  4. Override denyAccess() in a custom AccessControl subclass to redirect or return JSON instead of a bare 403.

Example fix

// before - logged-in non-admins get 403
'access' => [
    'class' => AccessControl::class,
    'only' => ['delete'],
    'rules' => [['actions' => ['delete'], 'allow' => true, 'roles' => ['admin']]],
],

// after - also allow editors, deny everyone else explicitly
'access' => [
    'class' => AccessControl::class,
    'only' => ['delete'],
    'rules' => [
        ['actions' => ['delete'], 'allow' => true, 'roles' => ['admin', 'editor']],
        ['allow' => false],
    ],
],
Defensive patterns

Strategy: validation

Validate before calling

// Before performing a restricted action, check the same rule data AccessControl uses
if (!Yii::$app->user->can('deletePost')) {
    throw new \yii\web\ForbiddenHttpException('You are not allowed to perform this action.');
}
// or probe the filter configuration before running the action
foreach ($this->getBehavior('access')->rules as $rule) {
    if ($rule->allows(Yii::$app->controller->action, Yii::$app->user, Yii::$app->request) !== false) {
        $allowed = true; break;
    }
}

Try / catch

use yii\web\ForbiddenHttpException;

try {
    return $this->runAction('delete');
} catch (ForbiddenHttpException $e) {
    Yii::$app->session->setFlash('error', 'Insufficient permissions.');
    return $this->redirect(['index']);
}

Prevention

When it happens

Trigger: An action covered by AccessControl's 'only'/'except' list where every rule evaluates false for a logged-in user: roles that the user lacks, 'matchCallback' returning false, verbs/IPs not matching; or a controller using AccessControl in an app where the 'user' component is disabled (user => false).

Common situations: RBAC permission not assigned to the user's role (only ['admin'] while user is 'editor'); matchCallback logic bugs (wrong comparison, inverted condition); forgetting that guests get a login redirect only when the User component exists - stateless APIs with a detached user always get 403; deploying new access rules before migrating auth assignments.

Related errors


AI-assisted analysis of yiisoft/yii2@66f00d18a2 (2026-08-17). Data as JSON: /api/errors/2df8b80d57ada763. Report an issue: GitHub.