Security

Symfony's Security component handles two related but distinct questions for every request: authentication ("who are you?") and authorization ("what are you allowed to do?"). Authentication figures out the identity behind a request — usually by checking a login session or token — while authorization decides whether that identity is permitted to reach a particular route or perform a particular action.

The security.yaml Configuration File

Most of the Security component's setup lives in config/packages/security.yaml. It defines the application's firewalls (which URL patterns require authentication and how), its user providers (where user accounts are loaded from, such as the Doctrine-mapped User entity), and the password hashing algorithm used for stored passwords. You won't hand-write most of this — Symfony Flex generates a working starting point when you install the security package — but knowing what lives here helps when something needs adjusting.

security:
    password_hashers:
        App\Entity\User: 'auto'
    firewalls:
        main:
            provider: app_user_provider
            form_login: true
Note: This YAML excerpt is illustrative, not the full schema — this website doesn't have Symfony installed, so nothing here executes live on this page. Copy real configuration into your own project's security.yaml.

Protecting a Route

Once a firewall and a set of roles exist, restricting an entire controller action to a specific role is a single PHP 8 attribute — no separate configuration file needed, in the same spirit as the routing and validation attributes covered earlier in this track.

<?php

namespace App\Controller;

use Symfony\Component\Security\Http\Attribute\IsGranted;

class ArticleController extends AbstractController
{
    #[IsGranted('ROLE_ADMIN')]
    public function delete(Article $article)
    {
        // only reached if the current user has ROLE_ADMIN
    }
}

The imperative equivalent — useful when the check depends on something only known partway through the method, such as whether the current user owns the specific article — calls denyAccessUnlessGranted() directly inside the action:

public function delete(Article $article)
{
    $this->denyAccessUnlessGranted('ROLE_ADMIN');

    // execution stops here with a 403 response for anyone lacking ROLE_ADMIN
}

Getting the Current User

Inside any controller extending AbstractController, the currently authenticated user (or null, if nobody is logged in) is available through a single method call — no manual session lookups required.

public function profile()
{
    $user = $this->getUser();

    return $this->render('user/profile.html.twig', ['user' => $user]);
}

Passwords Are Never Compared in Plaintext

Whatever algorithm is configured in security.yaml, password hashing and comparison always run through the injected PasswordHasherInterface — you hash a plaintext password once, when it's set, and store only the hash. Logging in never compares a submitted password to a stored password directly; it hashes the submitted value the same way and compares hashes instead. This is a basic security principle worth carrying into any framework, and Symfony's Security component simply automates it for you.

Next up: Head to Best Practices, the final page of this track, for a checklist that pulls everything together.