title: How to retrieve error message with getLastAuthenticationError() on login?
body: <p>I have tried implementing a simple login form with both Symfony Guard and Symfony Authentication provider but despite everything I tried, both variables $last_email and $error are always empty.</p>
  <p>I have followed this step by step: <a href="https://symfony.com/doc/4.4/security/form_login_setup.html" rel="nofollow noreferrer">https://symfony.com/doc/4.4/security/form_login_setup.html</a> and all of my LoginFormAuthenticator.php is identical. So is my controller and login.html.twig</p>
  <pre><code>public function login(AuthenticationUtils $authenticationUtils, Request $request, AuthorizationCheckerInterface $authChecker): Response
  {
      // get the login error if there is one
      $error = $authenticationUtils-&gt;getLastAuthenticationError();
      dump($error);
  
      // last username entered by the user
      $last_email = $authenticationUtils-&gt;getLastUsername();
  
      return $this-&gt;render('security/login.html.twig', [
          'last_email' =&gt; $last_email,
          'error'      =&gt; $error,
      ]);
  }
  </code></pre>
  <p>Here, even if the email does not exist or the password is invalid, $error is always null. Why?</p>
  <p>Here are the logs:</p>
  <blockquote>
  <p>[2020-08-23 11:53:35] request.INFO: Matched route &quot;login&quot;.
  {&quot;route&quot;:&quot;login&quot;,&quot;route_parameters&quot;:{&quot;_route&quot;:&quot;login&quot;,&quot;_controller&quot;:&quot;App\Controller\SecurityController::login&quot;},&quot;request_uri&quot;:&quot;http://localhost:8000/login&quot;,&quot;method&quot;:&quot;POST&quot;}
  [2020-08-23 11:53:35] security.DEBUG: Checking for guard
  authentication credentials. {&quot;firewall_key&quot;:&quot;main&quot;,&quot;authenticators&quot;:1}
  [2020-08-23 11:53:35] security.DEBUG: Checking support on guard
  authenticator.
  {&quot;firewall_key&quot;:&quot;main&quot;,&quot;authenticator&quot;:&quot;App\Security\LoginFormAuthenticator&quot;}
  [2020-08-23 11:53:35] security.DEBUG: Calling getCredentials() on
  guard authenticator.
  {&quot;firewall_key&quot;:&quot;main&quot;,&quot;authenticator&quot;:&quot;App\Security\LoginFormAuthenticator&quot;}
  [2020-08-23 11:53:35] security.DEBUG: Passing guard token
  information to the GuardAuthenticationProvider
  {&quot;firewall_key&quot;:&quot;main&quot;,&quot;authenticator&quot;:&quot;App\Security\LoginFormAuthenticator&quot;}
  [2020-08-23 11:53:35] security.INFO: Guard authentication failed.
  {&quot;exception&quot;:&quot;[object]
  (Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException(code:
  0):  at
  /src/Security/LoginFormAuthenticator.php:68)&quot;,&quot;authenticator&quot;:&quot;App\Security\LoginFormAuthenticator&quot;}
  [2020-08-23 11:53:35] security.DEBUG: The
  &quot;App\Security\LoginFormAuthenticator&quot; authenticator set the response.
  Any later authenticator will not be called
  {&quot;authenticator&quot;:&quot;App\Security\LoginFormAuthenticator&quot;}
  [2020-08-23 11:53:35] request.INFO: Matched route &quot;login&quot;.
  {&quot;route&quot;:&quot;login&quot;,&quot;route_parameters&quot;:{&quot;_route&quot;:&quot;login&quot;,&quot;_controller&quot;:&quot;App\Controller\SecurityController::login&quot;},&quot;request_uri&quot;:&quot;http://localhost:8000/login&quot;,&quot;method&quot;:&quot;GET&quot;}
  [2020-08-23 11:53:35] security.DEBUG: Checking for guard
  authentication credentials. {&quot;firewall_key&quot;:&quot;main&quot;,&quot;authenticators&quot;:1}
  [2020-08-23 11:53:35] security.DEBUG: Checking support on guard
  authenticator.
  {&quot;firewall_key&quot;:&quot;main&quot;,&quot;authenticator&quot;:&quot;App\Security\LoginFormAuthenticator&quot;}
  [2020-08-23 11:53:35] security.DEBUG: Guard authenticator does not
  support the request.
  {&quot;firewall_key&quot;:&quot;main&quot;,&quot;authenticator&quot;:&quot;App\Security\LoginFormAuthenticator&quot;}
  [2020-08-23 11:53:35] security.INFO: Populated the TokenStorage
  with an anonymous Token.</p>
  </blockquote>
  <p>My Security.yaml</p>
  <pre><code>security:
      access_denied_url: /
      encoders:
          App\Entity\User:
              algorithm: bcrypt
      # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
      providers:
          in_memory: { memory: ~ }
          our_db_provider:
              entity:
                  class: App\Entity\User
                  property: email
      firewalls:
          dev:
              pattern: ^/(_(profiler|wdt)|css|images|js)/
              security: false
          main:
              pattern:    ^/
              http_basic: ~
              provider: our_db_provider
              anonymous: ~
              form_login:
                  use_referer: true
                  csrf_token_generator: security.csrf.token_manager
              remember_me:
                  secret:   '%kernel.secret%'
                  lifetime: 604800 # 1 week in seconds
                  path:     /
                  name:     REMEMBERME
                  remember_me_parameter: _remember_me
              logout:
                  path:  /logout
                  target: /
              guard:
                  authenticators:
                      - App\Security\LoginFormAuthenticator
      # activate different ways to authenticate
  
      # activate different ways to authenticate
      # https://symfony.com/doc/current/security.html#firewalls-authentication
  
      # https://symfony.com/doc/current/security/impersonating_user.html
      # switch_user: true
  
      # Easy way to control access for large sections of your site
      # Note: Only the *first* access control that matches will be used
      role_hierarchy:
          ROLE_ADMIN:    [ROLE_USER, ROLE_INVESTOR, ROLE_STARTUP]
          ROLE_INVESTOR: [ROLE_USER]
          ROLE_STARTUP:  [ROLE_USER]
      access_control:
          - { path: ^/login$,             roles: IS_AUTHENTICATED_ANONYMOUSLY }
  </code></pre>
  <p>My LoginFormAuthenticator.php</p>
  <pre><code>class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
  {
      use TargetPathTrait;
  
      public const LOGIN_ROUTE = 'login';
  
      private $entityManager;
      private $urlGenerator;
      private $csrfTokenManager;
      private $passwordEncoder;
      private $flash;
  
      public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder, FlashBagInterface $flash)
      {
          $this-&gt;entityManager = $entityManager;
          $this-&gt;urlGenerator = $urlGenerator;
          $this-&gt;csrfTokenManager = $csrfTokenManager;
          $this-&gt;passwordEncoder = $passwordEncoder;
          $this-&gt;flash = $flash;
      }
  
      public function supports(Request $request)
      {
          return self::LOGIN_ROUTE === $request-&gt;attributes-&gt;get('_route')
              &amp;&amp; $request-&gt;isMethod('POST');
      }
  
      public function getCredentials(Request $request)
      {
          $credentials = [
              'email' =&gt; $request-&gt;request-&gt;get('email'),
              'password' =&gt; $request-&gt;request-&gt;get('password'),
              'csrf_token' =&gt; $request-&gt;request-&gt;get('_csrf_token'),
          ];
  
          $request-&gt;getSession()-&gt;set(
              Security::LAST_USERNAME,
              $credentials['email']
          );
  
          return $credentials;
      }
  
      public function getUser($credentials, UserProviderInterface $userProvider)
      {
          $token = new CsrfToken('authenticate', $credentials['csrf_token']);
          if (!$this-&gt;csrfTokenManager-&gt;isTokenValid($token)) {
  //            throw new InvalidCsrfTokenException();
          }
  
          $user = $this-&gt;entityManager-&gt;getRepository(User::class)-&gt;findOneBy(['email' =&gt; $credentials['email']]);
          dump($user);
          if (!$user) {
              // fail authentication with a custom error
              throw new CustomUserMessageAuthenticationException('Email could not be found.');
          }
  
          return $user;
      }
  
      public function checkCredentials($credentials, UserInterface $user)
      {
          return $this-&gt;passwordEncoder-&gt;isPasswordValid($user, $credentials['password']);
      }
  
      public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
      {
          if ($targetPath = $this-&gt;getTargetPath($request-&gt;getSession(), $providerKey)) {
              return new RedirectResponse($targetPath);
          }
  
           return new RedirectResponse($this-&gt;urlGenerator-&gt;generate('logged_in'));
      }
  
      protected function getLoginUrl()
      {
          return $this-&gt;urlGenerator-&gt;generate(self::LOGIN_ROUTE);
      }
  }
  </code></pre>
  <p>Any help is much appreciated. I'm using Symfony 4.4</p>
  <p>EDIT:
  So the login form WORKS - I can log in and log out. But if my email doesn't exist or if my credentials are invalid, no error message get displayed. Doing a var_dump on $error and $last_email returns NULL and empty string, always. Also, I tried to var dump $this-&gt;passwordEncoder-&gt;isPasswordValid($user, $credentials['password']); from my LoginFormAuthenticator in the checkCredentials method and if my credentials are invalid, i can see it returns false. So that works. But somehow, something seems broken in the background.</p>