Skip to content

docs(security): document voter decision reasons - #2333

Merged
soyuka merged 1 commit into
api-platform:4.4from
soyuka:docs/security-voter-reasons
Sep 13, 2026
Merged

docs(security): document voter decision reasons#2333
soyuka merged 1 commit into
api-platform:4.4from
soyuka:docs/security-voter-reasons

Conversation

@soyuka

@soyuka soyuka commented Sep 12, 2026

Copy link
Copy Markdown
Member

Summary

  • Documents F2 from the 4.4/5.0 docs audit: the access_decision variable (an instance of
    Symfony\Component\Security\Core\Authorization\AccessDecision) now available in security
    expressions, AccessDecision::getMessage(), and how a Symfony voter's reason (Vote::addReason())
    reaches the 403 problem response's detail field.
  • States plainly that this dynamic detail is gated by kernel.debug — it is only surfaced in
    dev/test; in prod the client gets a generic "Access Denied." unless an explicit
    securityMessage is set. Verified at src/State/ErrorProvider.php:89
    ($accessDeniedException->getDetail() ?? ($this->debug ? $accessDeniedException->getMessage() : 'Access Denied.'))
    and the %kernel.debug% wiring at src/Symfony/Bundle/Resources/config/api.php:307.
  • Documents F22: a short usage example for ApiPlatform\Metadata\Exception\AccessDeniedException
    (throwing it from a state processor with an explicit detail), giving the upgrade guide's existing
    deprecation note (core/upgrade-guide.md:61-64) somewhere to point to.

Ground truth

  • Core PR #8448 (commit cd67e0b23, "feat(symfony): expose voter reasons"), verified against
    upstream/4.4 of api-platform/core: ResourceAccessChecker::decide(),
    AccessCheckerProvider::provide(), ApiPlatform\Symfony\Security\Core\Authorization\ExpressionLanguageProvider
    (overrides is_granted() to forward access_decision), and vendor/symfony/security-core's
    AccessDecision/Vote/AuthorizationChecker classes.
  • Consistent with docs PR Update parameter security documentation to reflect that it throws AccessDeniedException #2320 (merged to 4.3), which documents that parameter-level security
    throws AccessDeniedException rather than silently ignoring the parameter.

Page choice

Added to symfony/security.md, not core/security.md. core/security.md is a 13-line stub that
only redirects to the Symfony/Laravel-specific pages; every other technical detail of this feature
(is_granted(), ResourceAccessChecker, Symfony's Voter/Vote API, AccessCheckerProvider) is
Symfony-only and already lives in symfony/security.md, right next to the existing "Hooking Custom
Permission Checks Using Voters" and "Configuring the Access Control Error Message" sections.

Test plan

  • npx prettier@3.9.5 --check "**/*.md" --prose-wrap always passes repo-wide
  • Line length checked (<= 400 chars)
  • Every code example checked against api-platform/core upstream/4.4 source

Core PR #8448 (cd67e0b23) adds the access_decision variable to security
expressions and AccessDecision::getMessage(); document how a voter's
reason reaches the client and that it is gated by kernel.debug. Also add
a usage example for ApiPlatform\Metadata\Exception\AccessDeniedException
(F22), the class the upgrade guide already points to.
@soyuka
soyuka force-pushed the docs/security-voter-reasons branch from 82a5bc5 to 5b825e5 Compare September 13, 2026 06:59
@soyuka
soyuka merged commit c0d9d24 into api-platform:4.4 Sep 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant