Why my jwt tokens never expire?

3.7k views Asked by At

I've inherited a Symfony project that uses this controller to authenticate users:

class TokenController extends FOSRestController
{
    public function postTokensAction(Request $request)
    {
        $username = $request->request->get('username');
        $password = $request->request->get('password');

        $user = $this->get('fos_user.user_manager')
                     ->findUserByUsername($username);

        if (!$user) {
            throw $this->createNotFoundException();
        }

        $passwordEncoder = $this->get('security.password_encoder');
        if(!$passwordEncoder->isPasswordValid($user, $password)) {
            throw $this->createAccessDeniedException();
        }

        $groups = ['foo', 'bar'];
        $context = SerializationContext::create()
                       ->setGroups($groups);

        $token = $this->get('lexik_jwt_authentication.encoder')
                      ->encode(['username' => $user->getUsername()]);

        $user = $this->get('jms_serializer')
                     ->toArray($user, $context);

        return new JsonResponse([
            'token' => $token,
            'user' => $user
        ]);
    }
}

And the customer requests an update: token should expire 10 seconds after the login. So, following the documentation, I added this listener.

<?php

namespace AppBundle\EventListener;

use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent;

class JWTCreatedListener
{
    public function onJWTCreated(JWTCreatedEvent $event)
    {
        $expiration = new \DateTime('now');
        $expiration->add(new \DateInterval('PT10S'));
        $payload = $event->getData();
        $payload['exp'] = $expiration->getTimestamp();
        $event->setData($payload);
    }
}

And, of course, I've marked the listener to observe the event

acme_api.event.jwt_created_listener:
    class: AppBundle\EventListener\JWTCreatedListener
    tags:
        - { name: kernel.event_listener, event: lexik_jwt_authentication.on_jwt_created, method: onJWTCreated }

If I get a token with Postman and use it to make following requests I can make those request for days and days. The token never expire. My JWTCreatedListener does not seem to work.

What's wrong?

2

There are 2 answers

0
chalasr On BEST ANSWER

They never expire because you are using a low level api which is the JWT encoder. As you can see (since you call it), encode() takes the payload. For getting token expiration, the payload must contain the exp claim with the expiration timestamp as value.
This is handled by the lexik_jwt_authentication.jwt_manager service which uses the value of the lexik_jwt_authentication.encoder.token_ttl config option to determine the expiration date. Set it and uses $this->get('lexik_jwt_authentication.jwt_manager')->create($user) for creating the token, then $this->get('lexik_jwt_authentication.jwt_manager')->decode($token) at time to decode/verify it.

Note that for using this bundle properly (allowing to hook into all the events it provides), you should consider using proper security configuration (as shown in the README) instead of doing this by hand in your controller.

1
sensorario On

The key is here:

$token = $this->get('lexik_jwt_authentication.encoder')
              ->encode(['username' => $user->getUsername()]);

I need to add another parameter to encode function:

$token = $this->get('lexik_jwt_authentication.encoder')
              ->encode([
                  'username' => $user->getUsername(),
                  'exp'      => (new \DateTime('+30 minute'))->getTimestamp(),
              ]);