NickHatBoecker
NickHatBoecker

Reputation: 33

Generate short lifetime JWT token with LexikJWTAuthenticationBundle

I try to secure some files via Symfony. Let's say I access them via the following url:

https://test.com/file/?token=AAAABBBBCCCC

I already implemented authorization via LexikJWTAuthenticationBundle. I log in; get an access token - this is working just fine. So I used my login access token to put in the url.

But login tokens have a far too long lifespan. So I thought about creating a short lifetime token (< 2 seconds), to just access the file once. As soon as I refresh the page, access to the file should be gone.

On the symfony page I found out how to create a token: $JWTManager->create($user) (https://symfony.com/bundles/LexikJWTAuthenticationBundle/current/7-manual-token-creation.html)

But I cannot configure lifespan of this token. This is usually configured in lexik_jwt_authentication.yaml, but I don't want change lifespan of the login token :/

I'm using Symfony 5.

Any ideas?

Upvotes: 0

Views: 1220

Answers (1)

NickHatBoecker
NickHatBoecker

Reputation: 33

I solved it now. First create a token and add any data to identify its use case. I use for example a scoped:

public function createToken(JWTTokenManagerInterface $jwt): JsonResponse
{
    $token = $jwt->createFromPayload(
        $this->getUser(),
        ['scope' => 'fileScope']
    );

    return new JsonResponse($token);
}

Then use an EventListener to set expiry date based on scope:

// EventListener/JWTCreatedListener.php

declare(strict_types=1);

namespace App\EventListener;

use App\Controller\Authentication\GetDocumentFileToken;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent;

/**
 * Class JWTCreatedListener
 */
class JWTCreatedListener
{
    /**
     * @param JWTCreatedEvent $event
     *
     * @return void
     */
    public function onJWTCreated(JWTCreatedEvent $event): void
    {
        $payload = $event->getData();

        if (($payload['scope'] ?? '') === 'fileScope') {
            $expiration = new \DateTime('+1 minute');
            $payload['exp'] = $expiration->getTimestamp();
        }

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

And then, in the controller where only specific scope tokens are allowed:

public function getDocumentFile(JWTTokenManagerInterface $jwt): JsonResponse
{
    $token = /* Get token from request or something */;
    $tokenData = $jwt->parse($token);

    if (($tokenData['scope'] ?? '') !== 'fileScope') {
        return new JsonResponse('Permission denied', 400);
    }

    // Token is valid and fileScope so output file
}

Upvotes: 2

Related Questions