markitosgv / JWTRefreshTokenBundle

Implements a Refresh Token system over Json Web Tokens in Symfony
MIT License
660 stars 159 forks source link

Remove previous refresh tokens on login #119

Open mbeineris opened 6 years ago

mbeineris commented 6 years ago

Perhaps I am missing something but Is there a reason why each login creates new db entry with new refresh token? Users end up with many tokens that are still valid. Perhaps on login have an option to remove old one or update existing one with new expiry date? Thanks in advance for shedding any light on my question.

Emroni commented 4 years ago

Attempted to fix this in PR #197

ayyouboulidi commented 4 years ago

Any news about your fix @Emroni ? or a workaround ?

Emroni commented 4 years ago

@ayyouboulidi unfortunately not..

A workaround could be to fire a cronjob every night or so to delete all but the last of each user.

ayyouboulidi commented 4 years ago

That's too bad but thanks for the answer @Emroni

BenPilliez commented 4 years ago

Hi, @ayyouboulidi  @Emroni you can overide the service :

` gesdinet.jwtrefreshtoken.send_token: class: App\EventListener\AttachRefreshTokenOnSuccessListener arguments: [ "@gesdinet.jwtrefreshtoken.refresh_token_manager", "%gesdinet_jwt_refresh_token.ttl%", "@validator", "@request_stack", "%gesdinet_jwt_refresh_token.user_identity_field%", "%gesdinet_jwt_refresh_token.token_parameter_name%", "%gesdinet_jwt_refresh_token.single_use%" ] tags:

`<?php

/*

namespace App\EventListener;

use Gesdinet\JWTRefreshTokenBundle\Model\RefreshTokenInterface; use Gesdinet\JWTRefreshTokenBundle\Model\RefreshTokenManagerInterface; use Gesdinet\JWTRefreshTokenBundle\Request\RequestRefreshToken; use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationSuccessEvent; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\PropertyAccess\PropertyAccessor;

class AttachRefreshTokenOnSuccessListener { /**

Nincha commented 1 year ago

Couldn't this be problematic if the user is supposed to be able to login from several devices?

Option would be great but should be optional imo. :)

antoine13330 commented 8 months ago

Hello everyone,

I managed to find a very fast forward solution for the issue ( without over engineering for our beginners ) :

config/services.yaml

parameters:

services:
    App\EventListener\AuthenticationSuccessListener:
        tags:
            - { name: kernel.event_listener, event: lexik_jwt_authentication.on_authentication_success, method: onAuthenticationSuccessResponse }

src/EventListener/AuthenticationSuccessListener.php

<?php
namespace App\EventListener;

use App\Entity\AuthUser;
use Lexik\Bundle\JWTAuthenticationBundle\Event\AuthenticationSuccessEvent;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\RefreshToken;

class AuthenticationSuccessListener
{
    private $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public function onAuthenticationSuccessResponse(AuthenticationSuccessEvent $event)
    {
        $data = $event->getData();
        $user = $event->getUser();

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

        $username = $user->getUsername();

        $refreshTokenRepository = $this->em->getRepository(RefreshToken::class);
        $refreshTokens = $refreshTokenRepository->findBy(['username' => $username], ['valid' => 'DESC']);

        array_shift($refreshTokens);

        foreach ($refreshTokens as $refreshToken) {
            $this->em->remove($refreshToken);
        }

        $this->em->flush();

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

Hope this helped some of y'all 🤠