Search code examples
phpsymfonysymfony4symfony5

How to create different the authentication error message in Symfony 5.4?


By default, it shows error "Invalid credentials.". I've already seen answers like "Go to translations, create security.en.yaml and type this:

# translations/security.en.yaml
'Invalid credentials.': 'Invalid email or password'

But how to create different errors? For example, "Invalid password" when password is wrong and "Email does not exists" when email is wrong. How to do it?


Solution

  • you must create custom authorization and exceptions.

    example: config/packages/security.yaml

    security:
        enable_authenticator_manager: true
        ...
        providers: 
        ...
        firewalls:
            ...
            client:
                pattern: ^/
                custom_authenticators:
                    - App\Security\ClientLoginFormAuthenticator
                logout:
                    path: store.account.logout
                    target: store.home
        access_control:
            ...
    

    src/Security/ClientLoginFormAuthenticator.php

    <?php
    declare(strict_types=1);
    
    namespace App\Security;
    
    use App\Repository\UserRepository;
    use App\Security\Exception\CustomException;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpFoundation\Response;
    use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
    use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
    use Symfony\Component\Security\Core\Exception\BadCredentialsException;
    use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator;
    use Symfony\Component\Security\Http\Authenticator\Passport\Badge\CsrfTokenBadge;
    use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
    use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
    use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
    use function in_array;
    
    class ClientLoginFormAuthenticator extends AbstractLoginFormAuthenticator
    {
        private const LOGIN_ROUTE = 'store.account.login';
    
        public function __construct(private UserRepository $userRepository, private UrlGeneratorInterface $urlGenerator)
        {}
    
        public function supports(Request $request): bool
        {
            return self::LOGIN_ROUTE === $request->attributes->get('_route')
                && $request->isMethod('POST');
        }
    
        public function authenticate(Request $request): Passport
        {
            $password = $request->request->get('_password');
            $username = $request->request->get('_username');
            $csrfToken = $request->request->get('_csrf_token');
    
            return new Passport(
                new UserBadge($username, function ($userIdentifier) {
                    $user = $this->userRepository->findOneBy(['email' => $userIdentifier]);
                    if ($user && in_array('ROLE_CLIENT', $user->getRoles(), true)) {
                        return $user;
                    }
    
                    //next condition
                    if($user && $user->getEmail() === '[email protected]') {
                        throw new CustomException();
                    }
    
                    throw new BadCredentialsException(); //default exception
                }),
                new PasswordCredentials($password),
                [new CsrfTokenBadge('authenticate', $csrfToken)]
            );
        }
    
        public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
        {
            return null;
        }
    
        protected function getLoginUrl(Request $request): string
        {
            return $this->urlGenerator->generate(self::LOGIN_ROUTE);
        }
    }
    

    src/Security/Exception/CustomException.php

    <?php
    namespace App\Security\Exception;
    
    use Symfony\Component\Security\Core\Exception\AuthenticationException;
    
    class CustomException extends AuthenticationException
    {
        /**
         * {@inheritdoc}
         */
        public function getMessageKey()
        {
            return 'My Message.';
        }
    }
    

    It works for me! :) Good luck!