title: Symfony 5 - Login with json_login; Login process is not working;
body: <p>first of all I want to let you know, that I'm new to Symfony.
  I'm on my way to move my PHP project from my own &quot;basic&quot; MVC to Symfony. The project is already running and working well, but I have some issues with adjusting to Symfony.</p>
  <p>I started with the basic skeleton, make:user and make:auth. The template worked well.
  But I failed converting the login process to AJAX and JSON.</p>
  <p>I followed this official tutorial: <a href="https://symfonycasts.com/screencast/api-platform-security/json-login" rel="nofollow noreferrer">https://symfonycasts.com/screencast/api-platform-security/json-login</a> as well as <a href="https://symfony.com/doc/current/security/json_login_setup.html" rel="nofollow noreferrer">https://symfony.com/doc/current/security/json_login_setup.html</a></p>
  <p>This is my security.yaml</p>
  <pre><code>security:
  encoders:
      App\Entity\User:
          algorithm: auto
  
  # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
  providers:
      # used to reload user from session &amp; other features (e.g. switch_user)
      app_user_provider:
          entity:
              class: App\Entity\User
              property: email
  firewalls:
      dev:
          pattern: ^/(_(profiler|wdt)|css|images|js)/
          security: false
      main:
          anonymous: true
          lazy: true
          provider: app_user_provider
  
          json_login:
              check_path: app_login
              username_path: email
              password_path: password
              
          guard:
              authenticators:
                  - App\Security\UserAuthenticator
          logout:
              path: app_logout
              # where to redirect after logout
              target: home
  </code></pre>
  <p>This is my Controller:</p>
  <pre><code>class SecurityController extends AbstractController
  {
      // methods={&quot;POST&quot;}
  
      /**
       * @Route(&quot;/api/login&quot;, name=&quot;app_login&quot;)
       */
      public function login(Request $request): Response
      {
          return $this-&gt;json([
              'user' =&gt; $this-&gt;getUser() ? $this-&gt;getUser()-&gt;getId(): null,
              'error' =&gt; 1,
              'content' =&gt; $request-&gt;getMethod()
              ]);
      }
  </code></pre>
  <p>I removed &quot;methods={&quot;POST&quot;}&quot; because of the Problem with the request method.</p>
  <p>First problem</p>
  <pre><code>curl -X POST -H &quot;Content-Type: application/json&quot; https://127.0.0.1:8000/api/login -d '{&quot;email&quot;: &quot;test@test.de&quot;, &quot;password&quot;: &quot;1234&quot;}
  </code></pre>
  <p>returns</p>
  <pre><code>    &lt;!DOCTYPE html&gt;
  &lt;html&gt;
      &lt;head&gt;
          &lt;meta charset=&quot;UTF-8&quot; /&gt;
          &lt;meta http-equiv=&quot;refresh&quot; content=&quot;0;url='/api/login'&quot; /&gt;
  
          &lt;title&gt;Redirecting to /api/login&lt;/title&gt;
      &lt;/head&gt;
      &lt;body&gt;
          Redirecting to &lt;a href=&quot;/api/login&quot;&gt;/api/login&lt;/a&gt;.
      &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  <p>content returns always &quot;GET&quot;</p>
  <pre><code>'content' =&gt; $request-&gt;getMethod()
  </code></pre>
  <p>user returns always NULL
  'user' =&gt; $this-&gt;getUser() ? $this-&gt;getUser()-&gt;getId(): null,</p>
  <p>Server Terminal Output:</p>
  <pre><code>[PHP        ] [Thu Mar 25 16:05:13 2021] 127.0.0.1:60846 [302]: POST /api/login
  [PHP        ] [Thu Mar 25 16:05:13 2021] 127.0.0.1:60846 Closing
  [PHP        ] [Thu Mar 25 16:05:13 2021] 127.0.0.1:60848 Accepted
  [PHP        ] [Thu Mar 25 16:05:13 2021] [info] Matched route &quot;app_login&quot;.
  [PHP        ] 
  [PHP        ] [Thu Mar 25 16:05:13 2021] [debug] Checking for guard authentication credentials.
  [PHP        ] 
  [PHP        ] [Thu Mar 25 16:05:13 2021] [debug] Checking support on guard authenticator.
  [PHP        ] 
  [PHP        ] [Thu Mar 25 16:05:13 2021] [debug] Guard authenticator does not support the request.
  </code></pre>
  <p>Where is my mistake?</p>
  <p>EDIT: Added UserAuthenticator.php</p>
  <pre><code>&lt;?php
  
  namespace App\Security;
  
  use App\Entity\User;
  use Doctrine\ORM\EntityManagerInterface;
  use Symfony\Component\HttpFoundation\RedirectResponse;
  use Symfony\Component\HttpFoundation\Request;
  use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
  use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
  use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
  use Symfony\Component\Security\Core\Security;
  use Symfony\Component\Security\Core\User\UserInterface;
  use Symfony\Component\Security\Core\User\UserProviderInterface;
  use Symfony\Component\Security\Csrf\CsrfToken;
  use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
  use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
  use Symfony\Component\Security\Guard\PasswordAuthenticatedInterface;
  use Symfony\Component\Security\Http\Util\TargetPathTrait;
  
  class UserAuthenticator extends AbstractFormLoginAuthenticator implements PasswordAuthenticatedInterface
  {
      use TargetPathTrait;
  
      public const LOGIN_ROUTE = 'app_login';
  
      private $entityManager;
      private $urlGenerator;
      private $csrfTokenManager;
      private $passwordEncoder;
  
      public function __construct(EntityManagerInterface $entityManager, UrlGeneratorInterface $urlGenerator, CsrfTokenManagerInterface $csrfTokenManager, UserPasswordEncoderInterface $passwordEncoder)
      {
          $this-&gt;entityManager = $entityManager;
          $this-&gt;urlGenerator = $urlGenerator;
          $this-&gt;csrfTokenManager = $csrfTokenManager;
          $this-&gt;passwordEncoder = $passwordEncoder;
      }
  
      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']]);
  
          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']);
      }
  
      /**
       * Used to upgrade (rehash) the user's password automatically over time.
       */
      public function getPassword($credentials): ?string
      {
          return $credentials['password'];
      }
  
      public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $providerKey)
      {
          if ($targetPath = $this-&gt;getTargetPath($request-&gt;getSession(), $providerKey)) {
              return new RedirectResponse($targetPath);
          }
  
          return new RedirectResponse($this-&gt;urlGenerator-&gt;generate('home'));
      }
  
      protected function getLoginUrl()
      {
          return $this-&gt;urlGenerator-&gt;generate(self::LOGIN_ROUTE);
      }
  }
  </code></pre>