The algorithm with the alias "" is not supported
NeuralClone opened this issue · 4 comments
Q | A |
---|---|
Symfony Version | 6.4.7 |
Bundle Version | 3.0.0 |
PHP Version | 8.3.7 |
Related issues/PRs | #1209, #1214 |
I've been attempting to configure this bundle to use the Web-Token feature as outlined in the documentation and have run into some issues.
I have the following configuration:
lexik_jwt_authentication:
secret_key: '%env(resolve:JWT_SECRET_KEY)%'
public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
pass_phrase: '%env(JWT_PASSPHRASE)%'
api_platform:
enabled: true
check_path: /api/login_check
username_path: username
password_path: password
encoder:
service: lexik_jwt_authentication.encoder.web_token
token_ttl: 3600
allow_no_expiration: false
clock_skew: 0
user_id_claim: username
token_extractors:
authorization_header:
enabled: true
prefix: Bearer
name: Authorization
cookie:
enabled: false
name: BEARER
query_parameter:
enabled: false
name: bearer
split_cookie:
enabled: false
cookies: { }
remove_token_from_body_when_cookies_used: true
set_cookies: { }
access_token_issuance:
enabled: true
signature:
algorithm: RS256
key: # some key
access_token_verification:
enabled: true
signature:
allowed_algorithms:
- RS256
keyset: # keyset
blocklist_token:
enabled: false
cache: cache.app
If encryption isn't enabled, an InvalidArgumentException
is always thrown by AccessTokenBuilder
whenever a request for a token is made. For example, the following always fails when encryption isn't enabled:
curl -X POST http://localhost/api/login_check \
-H "Content-Type: application/json" \
-d '{"username":"someusername","password":"somepassword"}'
The problematic lines of code appear to be here:
LexikJWTAuthenticationBundle/Services/WebToken/AccessTokenBuilder.php
Lines 68 to 71 in b20c4ae
$keyEncryptionAlgorithm
and $contentEncryptionAlgorithm
aren't automatically set to null
if they aren't defined and instead are set to empty strings. This always causes an exception to the thrown due to the encryption algorithm being set to an empty string. If I manually set both variables to null
before the above lines of code, my configuration works and a token is correctly sent in the response.
The encryption related service arguments are replaced here, but only if encryption is enabled:
Otherwise, they remain as empty strings, which doesn't appear to be the intention since it makes encryption mandatory.
I've attempted to directly set the encryption configuration options to null
as a possible workaround, but that causes a different exception to be thrown that says they can't be null
. That seems to directly contradict the service responsible for building tokens.
Am I missing an important configuration option/detail that addresses these issues or is this a bug? I've gone through the code and documentation in an attempt to find such an option and haven't had any luck. Is encryption supposed to be required when using the web-token feature?
I was finally able to get back to this today. After doing some additional debugging, the same problem exists in AccessTokenLoader
:
LexikJWTAuthenticationBundle/Services/WebToken/AccessTokenLoader.php
Lines 48 to 52 in b20c4ae
Likewise, the service arguments are set here:
The service is expecting the encryption algorithms and associated keysets to be null
but are empty strings instead. Therefore, verification always fails.
The easiest solution in both cases would probably be to make sure the appropriate arguments are set to null
if they aren't set in the configuration.
Workaround
I've been able to fix both of these issues in my Kernel
class by implementing CompilerPassInterface
and directly overriding the default values as described in the Symfony documentation: How to Work with Compiler Passes.
// src/Kernel.php
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
class Kernel extends BaseKernel implements CompilerPassInterface
{
use MicroKernelTrait;
// ...
public function process(ContainerBuilder $container): void
{
$accessTokenBuilderService = 'lexik_jwt_authentication.access_token_builder';
$accessTokenLoaderService = 'lexik_jwt_authentication.access_token_loader';
if ($container->hasDefinition($accessTokenBuilderService)) {
$container->getDefinition($accessTokenBuilderService)
->replaceArgument(5, null)
->replaceArgument(6, null)
->replaceArgument(7, null);
}
if ($container->hasDefinition($accessTokenLoaderService)) {
$container->getDefinition($accessTokenLoaderService)
->replaceArgument(9, null)
->replaceArgument(10, null)
->replaceArgument(11, null)
->replaceArgument(12, null);
}
}
// ...
}
This doesn't solve the core problem, but it's a reasonable and easy to implement workaround until it is fixed.
Thanks for the detailed report and workaround!
I'm going to look into this asap though you're welcome if you feel like trying to fix the root cause :)
You're welcome! I've created a pull request that addresses the root cause. Setting default values for the problematic arguments in the service configurations and changing the logic to look for empty arrays instead of null
in AccessTokenLoader
are the only changes that were needed.
This fix was originally suggested in #1209, but it wasn't fully implemented in #1214. Empty strings were set as default values and the logic wasn't updated in AccessTokenLoader
to address the empty arrays.
Are there any updates on this? Is there anything you'd like changed/reworked in the pull request I created?
I'm using the workaround I described above in projects that use this bundle and that's continued to work well. So, there's absolutely no rush. But it'd be nice to not have to use a compiler pass to fix the configuration.