Symfony
sponsored by SensioLabs
Menu
  • About
  • Documentation
  • Screencasts
  • Cloud
  • Certification
  • Community
  • Businesses
  • News
  • Download
  1. Home
  2. Documentation
  3. Components
  4. Security
  5. Authentication
  • Documentation
  • Book
  • Reference
  • Bundles
  • Cloud
Search by Algolia

Table of Contents

  • The Authentication Manager
  • Authentication Providers
    • Authenticating Users by their Username and Password
    • The Password Encoder Factory
    • Creating a custom Password Encoder
    • Using Password Encoders
  • Authentication Events
    • Authentication Success and Failure Events
    • Security Events

Authentication

Edit this page

Warning: You are browsing the documentation for Symfony 4.1, which is no longer maintained.

Read the updated version of this page for Symfony 6.2 (the current stable version).

Authentication

When a request points to a secured area, and one of the listeners from the firewall map is able to extract the user's credentials from the current Request object, it should create a token, containing these credentials. The next thing the listener should do is ask the authentication manager to validate the given token, and return an authenticated token if the supplied credentials were found to be valid. The listener should then store the authenticated token using the token storage:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;

class SomeAuthenticationListener implements ListenerInterface
{
    /**
     * @var TokenStorageInterface
     */
    private $tokenStorage;

    /**
     * @var AuthenticationManagerInterface
     */
    private $authenticationManager;

    /**
     * @var string Uniquely identifies the secured area
     */
    private $providerKey;

    // ...

    public function handle(GetResponseEvent $event)
    {
        $request = $event->getRequest();

        $username = ...;
        $password = ...;

        $unauthenticatedToken = new UsernamePasswordToken(
            $username,
            $password,
            $this->providerKey
        );

        $authenticatedToken = $this
            ->authenticationManager
            ->authenticate($unauthenticatedToken);

        $this->tokenStorage->setToken($authenticatedToken);
    }
}

Note

A token can be of any class, as long as it implements TokenInterface.

The Authentication Manager

The default authentication manager is an instance of AuthenticationProviderManager:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use Symfony\Component\Security\Core\Authentication\AuthenticationProviderManager;
use Symfony\Component\Security\Core\Exception\AuthenticationException;

// instances of Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface
$providers = [...];

$authenticationManager = new AuthenticationProviderManager($providers);

try {
    $authenticatedToken = $authenticationManager
        ->authenticate($unauthenticatedToken);
} catch (AuthenticationException $exception) {
    // authentication failed
}

The AuthenticationProviderManager, when instantiated, receives several authentication providers, each supporting a different type of token.

Note

You may write your own authentication manager, the only requirement is that it implements AuthenticationManagerInterface.

Authentication Providers

Each provider (since it implements AuthenticationProviderInterface) has a method supports() by which the AuthenticationProviderManager can determine if it supports the given token. If this is the case, the manager then calls the provider's method authenticate(). This method should return an authenticated token or throw an AuthenticationException (or any other exception extending it).

Authenticating Users by their Username and Password

An authentication provider will attempt to authenticate a user based on the credentials they provided. Usually these are a username and a password. Most web applications store their user's username and a hash of the user's password combined with a randomly generated salt. This means that the average authentication would consist of fetching the salt and the hashed password from the user data storage, hash the password the user has just provided (e.g. using a login form) with the salt and compare both to determine if the given password is valid.

This functionality is offered by the DaoAuthenticationProvider. It fetches the user's data from a UserProviderInterface, uses a PasswordEncoderInterface to create a hash of the password and returns an authenticated token if the password was valid:

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\Security\Core\Authentication\Provider\DaoAuthenticationProvider;
use Symfony\Component\Security\Core\User\UserChecker;
use Symfony\Component\Security\Core\User\InMemoryUserProvider;
use Symfony\Component\Security\Core\Encoder\EncoderFactory;

$userProvider = new InMemoryUserProvider(
    [
        'admin' => [
            // password is "foo"
            'password' => '5FZ2Z8QIkA7UTZ4BYkoC+GsReLf569mSKDsfods6LYQ8t+a8EW9oaircfMpmaLbPBh4FOBiiFyLfuZmTSUwzZg==',
            'roles'    => ['ROLE_ADMIN'],
        ],
    ]
);

// for some extra checks: is account enabled, locked, expired, etc.
$userChecker = new UserChecker();

// an array of password encoders (see below)
$encoderFactory = new EncoderFactory(...);

$daoProvider = new DaoAuthenticationProvider(
    $userProvider,
    $userChecker,
    'secured_area',
    $encoderFactory
);

$daoProvider->authenticate($unauthenticatedToken);

Note

The example above demonstrates the use of the "in-memory" user provider, but you may use any user provider, as long as it implements UserProviderInterface. It is also possible to let multiple user providers try to find the user's data, using the ChainUserProvider.

The Password Encoder Factory

The DaoAuthenticationProvider uses an encoder factory to create a password encoder for a given type of user. This allows you to use different encoding strategies for different types of users. The default EncoderFactory receives an array of encoders:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
use Acme\Entity\LegacyUser;
use Symfony\Component\Security\Core\Encoder\EncoderFactory;
use Symfony\Component\Security\Core\Encoder\MessageDigestPasswordEncoder;
use Symfony\Component\Security\Core\User\User;

$defaultEncoder = new MessageDigestPasswordEncoder('sha512', true, 5000);
$weakEncoder = new MessageDigestPasswordEncoder('md5', true, 1);

$encoders = [
    User::class       => $defaultEncoder,
    LegacyUser::class => $weakEncoder,
    // ...
];
$encoderFactory = new EncoderFactory($encoders);

Each encoder should implement PasswordEncoderInterface or be an array with a class and an arguments key, which allows the encoder factory to construct the encoder only when it is needed.

Creating a custom Password Encoder

There are many built-in password encoders. But if you need to create your own, it needs to follow these rules:

  1. The class must implement PasswordEncoderInterface;
  2. The implementations of encodePassword() and isPasswordValid() must first of all make sure the password is not too long, i.e. the password length is no longer than 4096 characters. This is for security reasons (see CVE-2013-5750), and you can use the isPasswordTooLong() method for this check:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    use Symfony\Component\Security\Core\Encoder\BasePasswordEncoder;
    use Symfony\Component\Security\Core\Exception\BadCredentialsException;
    
    class FoobarEncoder extends BasePasswordEncoder
    {
        public function encodePassword($raw, $salt)
        {
            if ($this->isPasswordTooLong($raw)) {
                throw new BadCredentialsException('Invalid password.');
            }
    
            // ...
        }
    
        public function isPasswordValid($encoded, $raw, $salt)
        {
            if ($this->isPasswordTooLong($raw)) {
                return false;
            }
    
            // ...
        }
    }

Using Password Encoders

When the getEncoder() method of the password encoder factory is called with the user object as its first argument, it will return an encoder of type PasswordEncoderInterface which should be used to encode this user's password:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// a Acme\Entity\LegacyUser instance
$user = ...;

// the password that was submitted, e.g. when registering
$plainPassword = ...;

$encoder = $encoderFactory->getEncoder($user);

// returns $weakEncoder (see above)
$encodedPassword = $encoder->encodePassword($plainPassword, $user->getSalt());

$user->setPassword($encodedPassword);

// ... save the user

Now, when you want to check if the submitted password (e.g. when trying to log in) is correct, you can use:

1
2
3
4
5
6
7
8
9
10
11
// fetch the Acme\Entity\LegacyUser
$user = ...;

// the submitted password, e.g. from the login form
$plainPassword = ...;

$validPassword = $encoder->isPasswordValid(
    $user->getPassword(), // the encoded password
    $plainPassword,       // the submitted password
    $user->getSalt()
);

Authentication Events

The security component provides 4 related authentication events:

Name Event Constant Argument Passed to the Listener
security.authentication.success AuthenticationEvents::AUTHENTICATION_SUCCESS AuthenticationEvent
security.authentication.failure AuthenticationEvents::AUTHENTICATION_FAILURE AuthenticationFailureEvent
security.interactive_login SecurityEvents::INTERACTIVE_LOGIN InteractiveLoginEvent
security.switch_user SecurityEvents::SWITCH_USER SwitchUserEvent

Authentication Success and Failure Events

When a provider authenticates the user, a security.authentication.success event is dispatched. But beware - this event will fire, for example, on every request if you have session-based authentication. See security.interactive_login below if you need to do something when a user actually logs in.

When a provider attempts authentication but fails (i.e. throws an AuthenticationException), a security.authentication.failure event is dispatched. You could listen on the security.authentication.failure event, for example, in order to log failed login attempts.

Security Events

The security.interactive_login event is triggered after a user has actively logged into your website. It is important to distinguish this action from non-interactive authentication methods, such as:

  • authentication based on your session.
  • authentication using a HTTP basic header.

You could listen on the security.interactive_login event, for example, in order to give your user a welcome flash message every time they log in.

The security.switch_user event is triggered every time you activate the switch_user firewall listener.

See also

For more information on switching users, see How to Impersonate a User.

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
We stand with Ukraine.
Version:
Save your teams and projects before they sink

Save your teams and projects before they sink

Check Code Performance in Dev, Test, Staging & Production

Check Code Performance in Dev, Test, Staging & Production

↓ Our footer now uses the colors of the Ukrainian flag because Symfony stands with the people of Ukraine.

Avatar of Florent Destremau, a Symfony contributor

Thanks Florent Destremau (@florentdestremau) for being a Symfony contributor

2 commits • 7 lines changed

View all contributors that help us make Symfony

Become a Symfony contributor

Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

Learn how to contribute

Symfony™ is a trademark of Symfony SAS. All rights reserved.

  • What is Symfony?
    • Symfony at a Glance
    • Symfony Components
    • Case Studies
    • Symfony Releases
    • Security Policy
    • Logo & Screenshots
    • Trademark & Licenses
    • symfony1 Legacy
  • Learn Symfony
    • Symfony Docs
    • Symfony Book
    • Reference
    • Bundles
    • Best Practices
    • Training
    • eLearning Platform
    • Certification
  • Screencasts
    • Learn Symfony
    • Learn PHP
    • Learn JavaScript
    • Learn Drupal
    • Learn RESTful APIs
  • Community
    • SymfonyConnect
    • Support
    • How to be Involved
    • Code of Conduct
    • Events & Meetups
    • Projects using Symfony
    • Downloads Stats
    • Contributors
    • Backers
  • Blog
    • Events & Meetups
    • A week of symfony
    • Case studies
    • Cloud
    • Community
    • Conferences
    • Diversity
    • Documentation
    • Living on the edge
    • Releases
    • Security Advisories
    • SymfonyInsight
    • Twig
    • SensioLabs
  • Services
    • SensioLabs services
    • Train developers
    • Manage your project quality
    • Improve your project performance
    • Host Symfony projects
    Deployed on
Follow Symfony
Search by Algolia