lexik / LexikJWTAuthenticationBundle

JWT authentication for your Symfony API
MIT License
2.53k stars 610 forks source link

Symfony 5.4 -> 6.4 upgrade problems #1216

Open eXsio opened 7 months ago

eXsio commented 7 months ago

Hello

I am in the process of upgrading from Symfony 5.4 to 6.4 and I'm stuck on Lexik:

  1. requiring security.authentication.manager Service that is no longer there. What am I doing wrong? I am using latest stable version - 2.20.3. LexikJWTAuthenticationExtension is loading the deprecated_51.xml file that contains a Service lexik_jwt_authentication.security.authentication.listener, which in turn requires security.authentication.manager that has been removed in Symfony 6.0. I don't see any logic that prevents this from happening. How can this version be compatible with Symfony 6.x?

  2. After (temporarily) commenting out the above service definition in the `deprecated_51.xml' file, I am facing another error: Class "Symfony\Component\Security\Guard\AuthenticatorInterface" not found while loading "Lexik\Bundle\JWTAuthenticationBundle\Security\Guard\JWTTokenAuthenticator".

    From what I can see, the security-guard package is not available for Symfony 6.4. How to proceed? Because either I am doing something terribly wrong, or the 2.20.3 version is not compatible with Symfony 6.

eXsio commented 7 months ago

OK so I think I've found a semi-workaround for the issue 1. I have multiple firewalls, so I've aliased one of them:

  security.authentication.manager:
    alias: 'security.authenticator.manager.api'

The contract of the Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface and Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface seem to be similar, and I was able to move on, but this is a pretty bad thing to do, because of the interfaces mismatch. How could that happen if the 2.20.3 version is supposedly compatible with Symfony 6?

Still stuck on problem number 2. After installing symfony/security-bundle with version 6.4.* I don't have Symfony\Component\Security\Guard\AuthenticatorInterface. I have Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface instead.

eXsio commented 7 months ago

OK I've changed the composer to require ^3.x-dev version, now it doesn't throw errors. I just have one question: why on earth the README for 2.20.3 states that It is compatible (and tested) with PHP 7.1+ on Symfony 4.x, 5.x, 6.x and 7.x.? This is extremely misleading.

flohw commented 7 months ago

Hi,

This is compatible with the given versions of php and SF. I am with SF6.4, PHP 8.3 and JWT 2.20.3 and it works properly.

You may have missed this part of an upgrade : https://github.com/lexik/LexikJWTAuthenticationBundle/blob/3.x/UPGRADE-2.0.md especially the listener section (latest item of the removed options in the configuration section)

eXsio commented 7 months ago

The thing is that I was not upgrading Lexik from 1.x to 2.x. I was on 2.20.3 and I've just bumped Symfony from 5.4 to 6.4. I don't want to argue or be disrespectful, but frankly I don't understand how 2.20.3 can possibly be compatible with 6.4, when:

Please help me understand how can this work? As soon as I downgrade back from 3.x to 2.20.3 I get the following error:

Executing script cache:clear --no-warmup [KO]
 [KO]
Script cache:clear --no-warmup returned with error code 1
!!
!!  In CheckExceptionOnInvalidReferenceBehaviorPass.php line 119:
!!
!!    The service "lexik_jwt_authentication.security.authentication.listener" has
!!     a dependency on a non-existent service "security.authentication.manager".
!!    Did you mean one of these: "security.authentication_utils", "security.authe
!!    nticator.manager.api", "security.authenticator.manager.admin"
flohw commented 7 months ago

Hi,

The bundle is compatible with both SF version but it requires to update your configuration to target right authenticator, handler, listener. Based on the error you provide, it seems a configuration has not been updated on security side. The authentication listener is deprecated, still there to be able to work with SF5.4. The services have been updated to work with SF6.4 but it requires to update your symfony configuration accordingly.

You can rollback your symfony version to 5.4, setup some tests on your authentication endpoint and look at what is marked as deprecated and update the configuration.

eXsio commented 7 months ago

Can you point me in the general direction that prevents Lexik from loading the deprecated Services? I've gone through the migration documents couple of times and still can't get rid of the error. Digging through the source files I can see that the authentication_listener config value has a default of deprecated lexik_jwt_authentication.security.authentication.listener and there is no piece of documentation I can find that tells what should this be set in Symfony 6.4. This Listener is dependant on a Service that no longer exists in 5.4.

As for the deprecations, I can see what is deptecated from looking at the code, but the deprecation messeges don't have any suggestions on what to use instead. It seems that the 2.x branch is by default configured for Symfony 5.4 and there is no documentation on how to configure it for 6.4.

flohw commented 7 months ago

This loads the deprecated services. So nothing should prevent the service loading. The service is loaded but the services it depends on (security.authentication.manager) does not exist on SF6.4.

The only thing I can think of is the migration guide I pointed earlier: no listener are required now as this is part of the authenticator role. Maybe your code uses the service too. If you need to have a listener, you should look at the lexik_jwt_authentication.on_jwt_created event (Event::JWT_CREATED) or maybe some other events depending on your needs.

eXsio commented 7 months ago

The thig is I'm not using any listeners, outside of Kernel Event Listeners for Events defined in Lexik\Bundle\JWTAuthenticationBundle\Events, just plain vanilla config. The fact that

The service is loaded but the services it depends on (security.authentication.manager) does not exist on SF6.4

causes the Symfony's CheckExceptionOnInvalidReferenceBehaviorPass to throw an error during the cache warmup/containter building. I understand Symfony's behavior, I don't understand why the service is being loaded unconditionally in the first place. Why not use the logic similar to the one in LexikJWTAuthenticationBundle and load the services only if a specific version of Symfony is detected?

Same goes for $loader->load('guard_authenticator.xml'); - this also causes an error:

 Class "Symfony\Component\Security\Guard\AuthenticatorInterface" not found while loading "Lexik\Bundle\JWTAuthenticationBundle\Security\Guard\JWTTokenAuthenticator".

I'm not explicitly using those services anywhere, but they are being loaded (but not instantiated, I've checked) while the Container is being built and the whole thing collapses.

chalasr commented 7 months ago

JWTTokenAuthenticator is based on Symfony Guard, that is not in 6.4 (it has been completely removed)

https://github.com/lexik/LexikJWTAuthenticationBundle/blob/v2.20.3/Security/Authenticator/JWTAuthenticator.php is what you're looking for I think.JWTListener is deprecated as per the deprecation of authentication listeners in Symfony Core (removed in favor of the new authenticator manager system in Symfony 7). Please double-check the docs for the right services to use while upgrading.

chalasr commented 7 months ago

Same goes for $loader->load('guard_authenticator.xml'); - this also causes an error:

This call as well as all Guard-related logics are disabled depending on the installed version of symfony/security-*. That is covered through automated tests (see CI).

eXsio commented 7 months ago

Sorry for being a pain in the butt, but can you point me to the code that is responsible for conditional loading of this call? Because all I can see is this straightforward load of the guard_authenticator.xml in the LexikJWTAuthenticationExtension class.

Same goes for the deprecated services here.