/symfony-security-voters
Symfony security voters — role hierarchy, voter pattern, access control, authorization, permissions, IsGranted attribute. Triggers on: security, voter, role, authorization, access control, permission, IsGranted, role hierarchy, RBAC
$ npx -y skills add aligundogdu/symfony-hexagonal-skill --skill symfony-security-voters --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/symfony-security-voters
Context preview
The summary Claude sees to decide when to auto-load this skill.
Symfony security voters — role hierarchy, voter pattern, access control, authorization, permissions, IsGranted attribute. Triggers on: security, voter, role, authorization, access control, permission, IsGranted, role hierarchy, RBAC
SKILL.md
symfony-security-voters.SKILL.mddescription: "Symfony security voters — role hierarchy, voter pattern, access control, authorization, permissions, IsGranted attribute. Triggers on: security, voter, role, authorization, access control, permission, IsGranted, role hierarchy, RBAC"
Symfony Security & Voters
You are an expert in Symfony security with Voters pattern within hexagonal architecture.
When to Activate
- User needs authorization on endpoints
- User asks about voters or role hierarchy
- User wants access control logic
- User mentions RBAC, permissions, or security
Core Rule: Every Endpoint Has a ROLE
**No endpoint is publicly accessible without explicit `#[IsGranted]` or Voter check.**
#[Route('/api/users', methods: ['GET'])]
#[IsGranted('ROLE_USER_LIST')] // ALWAYS required
public function list(): JsonResponse { ... }Role Hierarchy
Define roles in `security.yaml`:
security:
role_hierarchy:
ROLE_ADMIN: [ROLE_USER_CREATE, ROLE_USER_EDIT, ROLE_USER_DELETE, ROLE_USER_LIST, ROLE_USER_VIEW]
ROLE_MANAGER: [ROLE_USER_LIST, ROLE_USER_VIEW, ROLE_ORDER_MANAGE]
ROLE_USER: [ROLE_USER_VIEW]Naming Convention
- Module-scoped: `ROLE_{MODULE}_{ACTION}`
- Examples: `ROLE_USER_CREATE`, `ROLE_ORDER_VIEW`, `ROLE_REPORT_GENERATE`
Simple Cases: Use `#[IsGranted]`
#[IsGranted('ROLE_USER_CREATE')]
public function create(): JsonResponse { ... }Complex Cases: Use Voters
When authorization depends on the resource (e.g., "can this user edit THIS order?"):
namespace App\Infrastructure\{Module}\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
final class {Entity}Voter extends Voter
{
public const VIEW = 'VIEW';
public const EDIT = 'EDIT';
public const DELETE = 'DELETE';
protected function supports(string $attribute, mixed $subject): bool
{
return in_array($attribute, [self::VIEW, self::EDIT, self::DELETE])
&& $subject instanceof {Entity};
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof UserInterface) {
return false;
}
return match ($attribute) {
self::VIEW => $this->canView($subject, $user),
self::EDIT => $this->canEdit($subject, $user),
self::DELETE => $this->canDelete($subject, $user),
default => false,
};
}
private function canView({Entity} $entity, UserInterface $user): bool
{
// Owner or admin can view
return $entity->ownerId() === $user->getId()
|| in_array('ROLE_ADMIN', $user->getRoles());
}
private function canEdit({Entity} $entity, UserInterface $user): bool
{
return $entity->ownerId() === $user->getId();
}
private function canDelete({Entity} $entity, UserInterface $user): bool
{
return in_array('ROLE_ADMIN', $user->getRoles());
}
}Using Voter in Controller
#[Route('/{id}', methods: ['PUT'])]
public function update(string $id): JsonResponse
{
$order = $this->getOrder($id);
$this->denyAccessUnlessGranted('EDIT', $order);
// ... proceed
}References
See `references/` for detailed guides:
- `voter-patterns.md` — Full voter examples and testing
- `role-hierarchy.md` — Role hierarchy design patterns
Read more
description: "Symfony security voters — role hierarchy, voter pattern, access control, authorization, permissions, IsGranted attribute. Triggers on: security, voter, role, authorization, access control, permission, IsGranted, role hierarchy, RBAC"
Symfony Security & Voters
You are an expert in Symfony security with Voters pattern within hexagonal architecture.
When to Activate
- User needs authorization on endpoints
- User asks about voters or role hierarchy
- User wants access control logic
- User mentions RBAC, permissions, or security
Core Rule: Every Endpoint Has a ROLE
**No endpoint is publicly accessible without explicit `#[IsGranted]` or Voter check.**
#[Route('/api/users', methods: ['GET'])]
#[IsGranted('ROLE_USER_LIST')] // ALWAYS required
public function list(): JsonResponse { ... }Role Hierarchy
Define roles in `security.yaml`:
security:
role_hierarchy:
ROLE_ADMIN: [ROLE_USER_CREATE, ROLE_USER_EDIT, ROLE_USER_DELETE, ROLE_USER_LIST, ROLE_USER_VIEW]
ROLE_MANAGER: [ROLE_USER_LIST, ROLE_USER_VIEW, ROLE_ORDER_MANAGE]
ROLE_USER: [ROLE_USER_VIEW]Naming Convention
- Module-scoped: `ROLE_{MODULE}_{ACTION}`
- Examples: `ROLE_USER_CREATE`, `ROLE_ORDER_VIEW`, `ROLE_REPORT_GENERATE`
Simple Cases: Use `#[IsGranted]`
#[IsGranted('ROLE_USER_CREATE')]
public function create(): JsonResponse { ... }Complex Cases: Use Voters
When authorization depends on the resource (e.g., "can this user edit THIS order?"):
namespace App\Infrastructure\{Module}\Security;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
final class {Entity}Voter extends Voter
{
public const VIEW = 'VIEW';
public const EDIT = 'EDIT';
public const DELETE = 'DELETE';
protected function supports(string $attribute, mixed $subject): bool
{
return in_array($attribute, [self::VIEW, self::EDIT, self::DELETE])
&& $subject instanceof {Entity};
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof UserInterface) {
return false;
}
return match ($attribute) {
self::VIEW => $this->canView($subject, $user),
self::EDIT => $this->canEdit($subject, $user),
self::DELETE => $this->canDelete($subject, $user),
default => false,
};
}
private function canView({Entity} $entity, UserInterface $user): bool
{
// Owner or admin can view
return $entity->ownerId() === $user->getId()
|| in_array('ROLE_ADMIN', $user->getRoles());
}
private function canEdit({Entity} $entity, UserInterface $user): bool
{
return $entity->ownerId() === $user->getId();
}
private function canDelete({Entity} $entity, UserInterface $user): bool
{
return in_array('ROLE_ADMIN', $user->getRoles());
}
}Using Voter in Controller
#[Route('/{id}', methods: ['PUT'])]
public function update(string $id): JsonResponse
{
$order = $this->getOrder($id);
$this->denyAccessUnlessGranted('EDIT', $order);
// ... proceed
}References
See `references/` for detailed guides:
- `voter-patterns.md` — Full voter examples and testing
- `role-hierarchy.md` — Role hierarchy design patterns
A Claude Code plugin that enforces hexagonal architecture (ports & adapters) in Symfony projects. Works with both new projects (full scaffolding) and existing projects (progressive, module-by-module refactoring).
Other skills on symfony-hexagonal-skill.
- /symfony-api-response
Symfony API response standardization — JSON payload format, exception handling, controllers, REST endpoints, error responses, debug mode. Triggers on: API, endpoint, controller, response, error handling, JSON, REST, API response, exception subscriber, HTTP
Open skill - /symfony-cqrs-handlers
Symfony CQRS command/query handlers — commands, queries, handlers, bus configuration, use cases. Triggers on: command, query, handler, CQRS, bus, use case, command handler, query handler, message bus
Open skill - /symfony-doctrine-persistence
Symfony Doctrine persistence — repository adapters, entity mapping, migrations, transactions, database patterns. Triggers on: doctrine, repository, persistence, database, mapping, migration, ORM, entity manager, DBAL, transaction
Open skill - /symfony-domain-modeling
Symfony domain modeling — entities, value objects, domain events, aggregates, domain exceptions. Triggers on: entity, value object, domain event, aggregate, domain exception, domain model, domain logic, business rule, invariant
Open skill - /symfony-hexagonal-architecture
Symfony hexagonal architecture setup — project structure, module scaffolding, layer responsibilities, dependency rules. Triggers on: architecture, module, layer, hexagonal, scaffold, project structure, directory structure, new project, new module
Open skill - /symfony-messenger-async
Symfony Messenger async processing — message queues, retry strategies, failure transport, Symfony Scheduler, idempotency patterns, background jobs. Triggers on: messenger, async, queue, retry, scheduler, background job, worker, transport, message queue, cron, scheduled task
Open skill

