Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Programmatically generate a refresh token #322

Open
geoffroyp opened this issue May 3, 2022 · 6 comments
Open

Programmatically generate a refresh token #322

geoffroyp opened this issue May 3, 2022 · 6 comments

Comments

@geoffroyp
Copy link

geoffroyp commented May 3, 2022

Greetings,

Whenever we programmatically generate a JWT token in lexik/JWT (using the method listed here), no refresh token is generated.

Is there a way to achieve this? is there a event I could bind to and/or a service/method I could call to start the refresh_token generation process?

@demonzarov
Copy link

demonzarov commented May 14, 2022

Can this help you?

https://github.com/markitosgv/JWTRefreshTokenBundle/blob/master/Generator/RefreshTokenGeneratorInterface.php#L22

@geoffroyp
Copy link
Author

geoffroyp commented May 25, 2022

Hi, sorry for the late answer.

Yes, this method could be useful if I was just passing refresh token as an array key in my response, but unfortunately it's not the case. I am using httpOnly cookie and using this method directly forces me to build the http only cookie "by myself"

Isn't there another entry point that would take my whole JWTRefreshToken configuration into consideration? (httpOnly, domain, TTL, secure, path, same site, single use, ....)

@brettins
Copy link

This is how I did it. You'll have to be very careful as the maintainers of this package don't really consider programmatic management a priority, and didn't mark some things as deprecated, like moving the get function to the Manager Interface and it broke my code.

use Gesdinet\JWTRefreshTokenBundle\Generator\RefreshTokenGeneratorInterface;
use Gesdinet\JWTRefreshTokenBundle\Model\RefreshTokenManagerInterface;

class JwtTokenManager
{
    public function __construct(
        private RefreshTokenGeneratorInterface $refreshTokenGenerator,
        private RefreshTokenManagerInterface $refreshTokenManager,
        private JWTTokenManagerInterface $JWTManager,
        private EntityManagerInterface $em,
    ){}

....

    public function createAndSetUserJwtTokens($user) 
    {
        $token = $this->JWTManager->create($user);

        $refreshToken = $this->refreshTokenGenerator->createForUserWithTtl($user, SELF::TTL);
        $this->refreshTokenManager->save($refreshToken);

        $user->setRefreshToken($refreshToken->getRefreshToken());

        if ($token) {
            $user->setToken($token);
        }
        return $user;
    }

    public function refreshToken($refreshTokenString) {

        $refreshToken = $this->refreshTokenManager->get($refreshTokenString);
        if ($refreshToken && $refreshToken->isValid()) {
            $userRepository = $this->em->getRepository("App:User");
            $user = $userRepository->findOneBy(['id' => $refreshToken->getUsername()]);
            $token = $this->JWTManager->create($user);
            $user->setRefreshToken($refreshTokenString);
            $user->setToken($token);
            return $user;
        }
        throw new CustomException(ErrorCodes::RefreshTokenInvalid, "RefreshTokenInvalid");
    }

@nickbg321
Copy link

I'm implementing something similar myself and it works but it's not perfect. Because of how the package is currently designed, by implementing programmatic generation you effectively throw away some parts of the functionality it offers for no reason. For e.g. you have to manually take care of setting token TTL (the config value becomes useless). So while it works it definitely feels like you're using the package in a way it was not intended to be used.

@fico7489
Copy link

fico7489 commented Mar 1, 2023

@demonzarov thanks!!!!

@mbabker
Copy link
Contributor

mbabker commented May 9, 2023

Because of how the package is currently designed, by implementing programmatic generation you effectively throw away some parts of the functionality it offers for no reason. For e.g. you have to manually take care of setting token TTL (the config value becomes useless). So while it works it definitely feels like you're using the package in a way it was not intended to be used.

I wouldn't necessarily say this bundle isn't intended to support programmatic generation, but its original design heavily favors a very specific configuration and workflow (automatic generation after initial login using the lexik_jwt_authentication.on_authentication_success event and after refresh by proxying through to the LexikJWTAuthenticationBundle's services for a single firewall). And because it favors that specific workflow, it doesn't do well at other workflows, including:

  • Programmatic generation (the generator service requires you to pass through a TTL, if you want to use the config you have to dig through the bundle internals and know you need the gesdinet_jwt_refresh_token.ttl container param)
  • Multi-firewall support (no differentiator between a refresh token generated for [email protected] on two separate firewalls, no support for differing configurations (TTL, request param name, cookie config, etc.) between firewalls)

It's something I've thought on and off about for almost two years and I'm no closer to having a good idea how to improve those other workflows today than I was back then.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants