Updated June 2026. Tested on Symfony 7.x and PHP 8.4. Part of the Techalyst Symfony series.

Authentication answers one question: who is this user? Symfony's security system handles it, and while it has a reputation for being dense, the modern setup is mostly generated for you and the pieces are easy to name. Once you can see the User entity, the firewall, and the authenticator, logging users in stops feeling like a black box.

The User entity

Authentication starts with a class that represents your users, implementing UserInterface. The two methods that matter identify the user and list their roles:

class User implements UserInterface, PasswordAuthenticatedUserInterface
{
    #[ORM\Column(unique: true)]
    private string $email;

    #[ORM\Column]
    private string $password; // the hashed password

    public function getUserIdentifier(): string { return $this->email; }
    public function getRoles(): array { return ['ROLE_USER']; }
    public function getPassword(): string { return $this->password; }
}

The make:user command generates this for you, wired to Doctrine, so you rarely write it by hand.

security.yaml: providers and firewalls

The whole system is configured in config/packages/security.yaml. Two parts matter most. A provider tells Symfony where users come from, usually your User entity loaded by email. A firewall defines how a section of your app is protected:

security:
    password_hashers:
        App\Entity\User: 'auto'

    providers:
        app_user_provider:
            entity: { class: App\Entity\User, property: email }

    firewalls:
        main:
            provider: app_user_provider
            form_login:
                login_path: app_login
                check_path: app_login
            logout:
                path: app_logout

The firewall named main watches your routes, uses the entity provider to load users, and the form_login authenticator handles a login form.

Logging in

The form_login authenticator does the heavy lifting. You provide a login controller and template, and Symfony intercepts the form submission, loads the user by the identifier, checks the password against the hash, and starts the session. make:auth scaffolds the controller and form for you, so a working login is mostly configuration plus a template.

Passwords are never stored in plain text. The password_hashers config picks a strong algorithm, and when a user registers you hash their password with the UserPasswordHasherInterface:

$user->setPassword($hasher->hashPassword($user, $plainPassword));

The current user

Once logged in, you reach the authenticated user from a controller:

$user = $this->getUser();          // or null if anonymous

Or inject it straight into an action with the #[CurrentUser] attribute:

public function dashboard(#[CurrentUser] User $user): Response { /* ... */ }

In Twig, app.user gives you the same thing for templates.

Wrapping up

Symfony authentication comes down to a few named pieces: a User entity implementing UserInterface, a provider in security.yaml that loads users from it, and a firewall with an authenticator like form_login that logs them in. Passwords are hashed with the password hasher, never stored raw, and you reach the logged-in user with getUser or #[CurrentUser]. Lean on make:user and make:auth to generate the boilerplate. Knowing who the user is, is only half of security, deciding what they are allowed to do is authorization with voters.