Skip to content

[Security] Support voter reasons in the "access denied" responses #7331

Description

@j-schumann

Description
Symfony (since 7.3) supports Voters setting a "reason" for an access decision: symfony/symfony#59771
Please implement an option to output the reason(s) given by the Voter(s) when access to an endpoint is denied.

Example
ApiResource on the User entity with security property:

  new Delete(
      security: "is_granted('DELETE', object)",
  ),

UserVoter:

  case self::DELETE:
      if (null !== $subject->getAccount()) {
          $vote?->addReason('User has an associated account and cannot be deleted');
          return false;
      }

Possible problem response:

{
    detail: "User has an associated account and cannot be deleted",
    status: 403,
    title: "An error occurred",
    type: "/errors/403",
}

Or instead of modifying the detail, return a separate field that may contain a list of reasons, not just the last reason.

Details
APIP currently cannot output this reason when it throws an AccessDenied[Http]Exception in the AccessCheckerProvider because its ResourceAccessChecker uses the ExpressionLanguage, which currently has no support for specifying an AccessDecision object like Symfony\Component\Security\Core\Authorization\AuthorizationChecker::isGranted has, that could later be evaluated for the reasons.

APIP's ResourceAccessChecker has its own $authorizationChecker, which could be accessed after evaluating the expression. This $authorizationChecker has an $accessDecisionStack, which is sadly empty and private.
But it also has a (private) $accessDecisionManager, which again has an $accessDecisionStack. And this stack has the AccessDecision object with all votes and reasons, but I have no idea how APIP could access this. I hope someone has a better idea than overwriting all those classes/services with custom versions to allow access to those fields.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions