Symfony Roles & Permissions: A Complete Tutorial (Beginner-Friendly)

Author

Kritim Yantra

Apr 18, 2025

Symfony Roles & Permissions: A Complete Tutorial (Beginner-Friendly)

Managing user access is crucial for web applications. Symfony provides a powerful role-based access control (RBAC) system to restrict what users can do.

In this guide, you’ll learn:
✅ How to define roles in Symfony
✅ Restricting routes by roles
✅ Creating custom permissions with voters
✅ Best practices for security

Let’s build a secure role-based system step by step!


1. Understanding Symfony Roles

What Are Roles?

Roles define user access levels (e.g., ROLE_USER, ROLE_ADMIN).

Default Roles in Symfony

  • ROLE_USER → Basic authenticated user
  • ROLE_ADMIN → Full access

Where Are Roles Stored?

In the User entity (generated by make:user):

// src/Entity/User.php  
#[ORM\Column(type: 'json')]  
private array $roles = [];  

public function getRoles(): array  
{  
    $roles = $this->roles;  
    $roles[] = 'ROLE_USER'; // Every user has ROLE_USER by default  
    return array_unique($roles);  
}  

2. Assigning Roles to Users

Manually Assigning Roles

Edit a user in the database:

UPDATE user SET roles = '["ROLE_ADMIN"]' WHERE id = 1;

Programmatically (e.g., in Registration)

// src/Controller/RegistrationController.php  
$user->setRoles(['ROLE_USER']); // Default role  

Promoting a User to Admin

$user->setRoles(['ROLE_ADMIN', 'ROLE_USER']);

3. Restricting Access by Role

Method 1: In security.yaml

# config/packages/security.yaml  
security:  
    access_control:  
        - { path: ^/admin, roles: ROLE_ADMIN }  
        - { path: ^/profile, roles: ROLE_USER }  

Method 2: In Controllers (Annotations)

// src/Controller/AdminController.php  
use Symfony\Component\Security\Http\Attribute\IsGranted;  

#[IsGranted('ROLE_ADMIN')]  
public function adminDashboard(): Response  
{  
    return $this->render('admin/dashboard.html.twig');  
}  

Method 3: Twig Templates

{% if is_granted('ROLE_ADMIN') %}  
    <a href="/admin">Admin Panel</a>  
{% endif %}  

4. Creating Custom Permissions with Voters

Sometimes, roles aren’t enough (e.g., "Can this user edit this post?"). For fine-grained control, use Voters.

Step 1: Generate a Voter

php bin/console make:voter

Name it PostVoter.

Step 2: Define Permissions

Edit src/Security/Voter/PostVoter.php:

protected function supports(string $attribute, mixed $subject): bool  
{  
    return in_array($attribute, ['EDIT', 'DELETE']) && $subject instanceof Post;  
}  

protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool  
{  
    $user = $token->getUser();  
    if (!$user instanceof User) return false;  

    $post = $subject;  
    return match ($attribute) {  
        'EDIT' => $user === $post->getAuthor() || in_array('ROLE_ADMIN', $user->getRoles()),  
        'DELETE' => in_array('ROLE_ADMIN', $user->getRoles()),  
        default => false,  
    };  
}  

Step 3: Use the Voter in a Controller

#[IsGranted('EDIT', subject: 'post')]  
public function edit(Post $post): Response  
{  
    // Only the author or admin can edit  
}  

5. Hierarchical Roles (Role Inheritance)

Define role hierarchy in security.yaml:

security:  
    role_hierarchy:  
        ROLE_ADMIN: [ROLE_USER, ROLE_MODERATOR]  
        ROLE_MODERATOR: [ROLE_USER]  

Now:

  • Admins automatically have ROLE_MODERATOR and ROLE_USER.
  • Moderators have ROLE_USER.

6. Testing Roles & Permissions

Check Roles in PHP

$this->isGranted('ROLE_ADMIN'); // Returns true/false  

Mocking Users in Tests

$user = new User();  
$user->setRoles(['ROLE_ADMIN']);  
$this->client->loginUser($user);  

Best Practices for Symfony Security

🔹 Always use ROLE_ prefix (Symfony convention).
🔹 Prefer voters over multiple roles for complex rules.
🔹 Never store sensitive logic in Twig (handle in PHP).
🔹 Use $this->denyAccessUnlessGranted() for quick checks.


Final Thoughts

You’ve now mastered Symfony’s role and permission system!

Recap:

✅ Defined roles and restricted routes
✅ Created custom permissions with voters
✅ Used role hierarchy for inheritance

Next Steps:

➡️ Try API tokens for stateless auth (lexik/jwt-authentication-bundle)
➡️ Explore Symfony ACL for advanced permissions

LIVE MENTORSHIP ONLY 5 SPOTS

Laravel Mastery
Coaching Class Program

KritiMyantra

Transform from beginner to Laravel expert with our personalized Coaching Class starting June 20, 2025. Limited enrollment ensures focused attention.

Daily Sessions

1-hour personalized coaching

Real Projects

Build portfolio applications

Best Practices

Industry-standard techniques

Career Support

Interview prep & job guidance

Total Investment
$200
Duration
30 hours
1h/day

Enrollment Closes In

Days
Hours
Minutes
Seconds
Spots Available 5 of 10 remaining
Next cohort starts:
June 20, 2025

Join the Program

Complete your application to secure your spot

Application Submitted!

Thank you for your interest in our Laravel mentorship program. We'll contact you within 24 hours with next steps.

What happens next?

  • Confirmation email with program details
  • WhatsApp message from our team
  • Onboarding call to discuss your goals

Tags

Comments

No comments yet. Be the first to comment!

Please log in to post a comment:

Sign in with Google

Related Posts