Wouter De Jong
Contributed by Wouter De Jong in #33558 , #36570 and #36574

Symfony 5.1 will include a new Security system as one of its biggest new features. After several months of planning, discussions and hard work, we could finish it on time for Symfony 5.1 as an experimental feature.

The main differences with respect to the previous system are:

1) Removed everything but Guards

In the new Security system, there's only one listener that passes the request to an authenticator manager provided by Symfony. That manager takes care of session management, storing the token, "Remember me" functionality, etc.

Everything is related to a single concept and interface: authenticators. This simplifies the internals of the Security component and makes everything easier to understand for developers.

2) Moved to an event-based system

The Security component didn't use Symfony events to extend all its features. The new system changes that and it's based on three events:

  • CheckPassportEvent, this is the main event and checks the validity of the given credentials (a password, a certificate, a CSRF token, etc.)
  • LoginSuccessEvent, dispatched when credentials are valid.
  • LoginFailureEvent, dispatched when credentials are wrong.

That's all! Three simple events give you all the flexibility needed by your applications.

3) Next generation Guards

Security Guards were introduced in Symfony 2.8 via the GuardAuthenticatorInterface. The new Security system allows to simplify some Guard features and improves others. For starters, the checkCredentials() method is removed and the getCredentials() and getUser() methods have been merged into a method called authenticate().

This introduces a couple of new concepts:

  • Passport, the authenticate() method returns a "security passport" that contains the user object and any credentials needed to authenticate it;
  • Badges, the extra information needed by the passport.

Passports and badges are used by listeners of the CheckPassportEvent, which will validate and check the passport and all its badges. If all badges are resolved, the user is successfully authenticated.

Here's a simplified example of the new system in action when used in a login form:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;

class FormAuthenticator implements AuthenticatorInterface
{
    // ...

    public function authenticate(Request $request): PassportInterface
    {
        // find a user based on an "email" form field
        $user = $this->userRepository->findOneByEmail($request->get('email'));
        if (!$user) {
            throw new UsernameNotFoundException();
        }

        return new Passport($user, new PasswordCredentials($request->get('password')), [
            // and CSRF protection using a "csrf_token" field
            new CsrfTokenBadge('loginform', $request->get('csrf_token')),

            // and add support for upgrading the password hash
            new PasswordUpgradeBadge($request->get('password'), $this->userRepository)
        ]);
    }
}

The new Security system is disabled by default, but you can enable it as follows:

1
2
3
4
# config/packages/security.yaml
security:
    # ...
    enable_authenticator_manager: true

We'll revamp all Symfony Doc articles about security very soon to start using this new Security system. Meanwhile, you can read the following blog post: Meet the new Symfony Security: Authenticators published by Wouter De Jong, the main developer behind this new Security system. This article was completely based on Wouter's blog post.

Published in #Living on the edge