Hello.
It's quite hard to provide translated error message generated by this bundle. For example message "Bad credentials" is not passed through translator as it is with similar message in Security Bundle of the Symfony (link).
What do you think about this change? If it's acceptable, then I can prepare PR.
Thanks, Vlad.
I don't think there is a need for change in the bundle. The "Bad credentials" message usually comes from Exception and I think Exception messages are for developers and not for end users.
Maybe a decorator of AuthenticationFailureHandler will be the best solution among many others.
@EresDev I did it in this way, but for me, it's a little bit overhead to invent an decorator/listener to replace the message provided by bundle. For me, security bundle is the great example in this case, but you decide.
Here is one quick solution. Simple inheritance.
<?php
namespace App\ThirdParty\Security\Lexik;
use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationFailureEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Events;
use Lexik\Bundle\JWTAuthenticationBundle\Response\JWTAuthenticationFailureResponse;
use Lexik\Bundle\JWTAuthenticationBundle\Security\Http\Authentication\AuthenticationFailureHandler;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class TranslatedAuthenticationFailureHandler extends AuthenticationFailureHandler
{
private $translator;
public function __construct(EventDispatcherInterface $dispatcher, TranslatorInterface $translator)
{
parent::__construct($dispatcher);
$this->translator = $translator;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
// $event = new AuthenticationFailureEvent(
// $exception,
// new JWTAuthenticationFailureResponse($exception->getMessage())
// );
$event = new AuthenticationFailureEvent(
$exception,
new JWTAuthenticationFailureResponse(
$this->translator->trans('authentication_failure_error_message')
)
);
if ($this->dispatcher instanceof ContractsEventDispatcherInterface) {
$this->dispatcher->dispatch($event, Events::AUTHENTICATION_FAILURE);
} else {
$this->dispatcher->dispatch(Events::AUTHENTICATION_FAILURE, $event);
}
return $event->getResponse();
}
}
security.yaml
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
login:
pattern: ^/login
stateless: true
anonymous: true
provider: custom_provider
json_login:
check_path: /login_check
username_path: email
password_path: password
success_handler: lexik_jwt_authentication.handler.authentication_success
failure_handler: App\ThirdParty\Security\Lexik\TranslatedAuthenticationFailureHandler
Yep, I did this in the same way, but for me, it's still overhead just for one message.
Well, that is all I got. If you find some better way, don't forget to share.
Extending the auth failure handler is a bit overhead to me.
Just add an event listener or subscriber for lexik_jwt_authentication.on_authentication_failure event as described here for example:
https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Resources/doc/2-data-customization.md#eventsauthentication_failure---customizing-the-failure-response-body
and then update the response message with translated one.
As an example:
namespace App\EventSubscriber;
use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationFailureEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Response\JWTAuthenticationFailureResponse;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class TranslateJWTAuthenticationFailureResponse implements EventSubscriberInterface
{
/** @var TranslatorInterface */
private $translator;
public function __construct(TranslatorInterface $translator)
{
$this->translator = $translator;
}
public static function getSubscribedEvents(): array
{
return [
'lexik_jwt_authentication.on_authentication_failure' => 'onAuthenticationFailureResponse',
];
}
public function onAuthenticationFailureResponse(AuthenticationFailureEvent $event): void
{
/** @var JWTAuthenticationFailureResponse $response */
$response = $event->getResponse();
$response->setMessage(
$this->translator->trans(
$response->getMessage()
)
);
}
}
and add required translations:
# translations/messages.ru.yml
'Invalid credentials.': "Неверный адрес электронной почты или пароль"
Most helpful comment
Extending the auth failure handler is a bit overhead to me.
Just add an event listener or subscriber for
lexik_jwt_authentication.on_authentication_failureevent as described here for example:https://github.com/lexik/LexikJWTAuthenticationBundle/blob/master/Resources/doc/2-data-customization.md#eventsauthentication_failure---customizing-the-failure-response-body
and then update the response message with translated one.
As an example:
and add required translations: