1

Im using JWT in my application with the lexikjwtauthbundle. I have created a service in API Platform and when I use the login service, I send the email and the password and it returns the token correctly among another user data.

picture of the login service in API Platform

My application has permissions determined by roles, however, I dont know how I can store the JWT token value and send it on the following requests using the Authorization header Bearer. I tried several things like creating an event listener and try to save the info of the response body on the header

<?php

namespace App\EventListener;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;

class TokenListener implements EventSubscriberInterface
{
    private $jwtManager;

    public function __construct(JWTTokenManagerInterface $jwtManager)
    {
        $this->jwtManager = $jwtManager;
    }

    public function onKernelResponse(ResponseEvent $event)
    {
        $response = $event->getResponse();

        // Verificar que la respuesta sea una respuesta vĂ¡lida.
        if (!$response instanceof Response) {
            return;
        }
    
        // Obtener el cuerpo de la respuesta.
        $body = $response->getContent();
    
        // Decodificar el objeto JSON del cuerpo de la respuesta.
        $data = json_decode($body, true);
    
        // Verificar si el objeto JSON contiene una clave 'token' y obtener su valor.
        $token = isset($data['token']) ? $data['token'] : null;
    
        // Establecer el valor del token en el encabezado 'Authorization' de la siguiente solicitud.
        if ($token) {
            $jwt = $this->jwtManager->create($token);
            $event->getRequest()->headers->set('Authorization', 'Bearer ' . $jwt);
        }
    }

    public static function getSubscribedEvents()
    {
        return [
            'kernel.response' => 'onKernelResponse',
        ];
    }
}

and define this event in the services.yaml

App\EventListener\TokenListener:
        tags:
            - { name: kernel.event_subscriber }

    lexik_jwt_authentication.token_extractor:
        class: Lexik\Bundle\JWTAuthenticationBundle\TokenExtractor\AuthorizationHeaderTokenExtractor
        arguments:
            - 'Bearer'
            - 'Authorization'

    lexik_jwt_authentication.jwt_manager:
        class: Lexik\Bundle\JWTAuthenticationBundle\Services\JWTManager
        arguments:
            - '@lexik_jwt_authentication.encoder'
            - '@event_dispatcher'
            - '@lexik_jwt_authentication.key_loader'
            - '@lexik_jwt_authentication.token_extractor'

I'm still a very new programmer and not familiar with symfony, maybe i'm making it more complicated than it really is. So I would greatly appreciate advice and above all an example of how I can do it. More info of files to create the token below.

<?php

namespace App\EventListener;

use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent;
use Symfony\Component\HttpFoundation\RequestStack;

class JWTCreatedListener
{
        /**
         * @var RequestStack
         */
        private $requestStack;

        /**
         * @param RequestStack $requestStack
         */
        public function __construct(RequestStack $requestStack)
        {
            $this->requestStack = $requestStack;
        }

        /**
         * @param JWTCreatedEvent $event
         *
         * @return void
         */
        public function onJWTCreated(JWTCreatedEvent $event)
        {
            $request = $this->requestStack->getCurrentRequest();

            $payload       = $event->getData();
            $payload['ip'] = $request->getClientIp();

            $event->setData($payload);

            $header        = $event->getHeader();
            $header['cty'] = 'JWT';

            $event->setHeader($header);
        }
    }
<?php

namespace app\EventListener;

use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationSuccessEvent;
use App\Entity\Usuarios;

class LoginSuccessListener
{
    

    public function onLoginSuccess(AuthenticationSuccessEvent $event): void
    {
        $user = $event->getUser();
        $payload = $event->getData();




        if (!$user instanceof Usuarios) {
            return;
        }

        $payload['user'] = array(
            'id' => $user->getId(),
            'Nombre' => $user->getNombre(),
            'Apellido1' => $user->getApellido1(),
            'Apellido2' => $user->getApellido2(),
            'Fechanacimiento' => $user->getFechaNacimiento(),
            'Nif' => $user->getNif(),
            'Sexo' => $user->getSexo(),
            'Disponibilidad' =>$user->isDisponibilidad(),
            'email' => $user->getEmail(),
            'NombreVia' => $user->getNombreVia(),
            'Numero' => $user->getNumero(),
            'Puerta' => $user->getPuerta(),
            'Piso' => $user->getPiso(),
            'Bloque' => $user->getBloque(),
            'Escalera' => $user->getEscalera(),
            'Telefono' => $user->getTelefono(),
            'Codigopostal' => $user->getCodigopostal(),
            'Usuariosmunicipios' => $user->getUsuariosmunicipiosaid(),
            'Provincia' => $user->getUsuariosprovincias(),
            'Tipo_rol' => $user->getRoles()
            

        );

        $event->setData($payload);
    }
}

1 Answers1

0

There is no correct answer to your question since it's a misuse of how jwt token should be used.

JWT Token exist to be used instead traditional auth system.
Instead of openning a user session after a tradionnal login, it is more like providing an "access key" each time you ask something to your backend.

A tradionnal usecase is to retrieve jwt token after a login (first screenshot). Then store on user end (like cookie or local storage). After that, each time your call your api from frontend, you have to provide this stored jwt token in the header of the request.
In your case you try to add it after the request was received by the server on your backend : don't do that.

Be carefull because by default jwt token of lexik has a 1 hour lifetime. (This is great don't change that). So you will need to relogin (bad way) or refresh the token each time it expire.

Look at https://github.com/markitosgv/JWTRefreshTokenBundle for this.

Basically here is a simplified list of what it happen on frontend:

  1. Login & store the token in local storage.
  2. On each api call, add the token to the header of your request.
  3. If the call return a 401 try to refresh the token.
  4. If the refresh return a 401, redirect user to login.
  5. If the resresh work, store the new token and make the main request again
ThomasL
  • 749
  • 4
  • 12