Reference / Symfony
/

Security: Voters

Voters answer "can THIS user do X to THIS object?" — the place for fine-grained, business-logic authorization.

Intermediate
  • Extend `Voter` and implement `supports($attribute, $subject)` and `voteOnAttribute($attribute, $subject, $token)`.
  • Trigger checks with `$this->isGranted('EDIT', $post)` in controllers or `is_granted('EDIT', post)` in Twig.
  • The `#[IsGranted('EDIT', subject: 'post')]` attribute on a controller method does the same, declaratively.
  • The decision strategy decides how multiple voters combine (default: affirmative — one GRANT wins).
  • Use voters instead of stuffing role checks into controllers — they\'re testable and centralize the rule.
class PostVoter extends Voter
{
    protected function supports(string $attr, mixed $subject): bool
    {
        return $attr === 'EDIT' && $subject instanceof Post;
    }

    protected function voteOnAttribute(string $attr, mixed $subject, TokenInterface $token): bool
    {
        $user = $token->getUser();
        return $user instanceof User && $subject->getAuthor() === $user;
    }
}

Common gotchas

  • Roles vs permissions: roles like ROLE_ADMIN are coarse. Object-level permissions belong in voters.
  • If `supports()` returns false the voter abstains — make sure the attribute and subject types are checked correctly.