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

JWT cookies not working with custom encoder #1233

Open
charlieandroid55 opened this issue Jul 30, 2024 · 5 comments
Open

JWT cookies not working with custom encoder #1233

charlieandroid55 opened this issue Jul 30, 2024 · 5 comments

Comments

@charlieandroid55
Copy link

The issue is that when I create a custom encoder that takes the token generated by encoder.lcobucci and re-encrypts it, the cookies don't work, but the headers do. From what I've been able to verify, is because the cookies call a JWTSplitter class, and since the new token is encrypted, it doesn't have the JWT format (header.payload.signature). What's curious is that the headers don't call this class, so the custom encoder can encode and decode without any problems.

Is there any way to create any cookie provider?

Can JWTCookieProvider class use the encoders before calling JWTSplitter?

I'm using the following configuration:

lexik_jwt_authentication:
    user_id_claim: user_identifier
    secret_key: "%env(resolve:JWT_SECRET_KEY)%"
    public_key: "%env(resolve:JWT_PUBLIC_KEY)%"
    pass_phrase: "%env(JWT_PASSPHRASE)%"
    token_ttl:  3600
    remove_token_from_body_when_cookies_used: false
    
    set_cookies:
        BEARER: 
            samesite: none
            path: /
            domain: null 
            secure: true 
            httpOnly: true
            partitioned: false

    token_extractors:
        authorization_header:
            enabled: true
            prefix: Bearer
            name: Authorization
        cookie:
            enabled: true
            name: BEARER

    encoder:
        service: App\Security\JwtCustomEncoder

    blocklist_token:
        enabled: true
        cache: cache.app

Custom encoder

<?php
declare(strict_types=1);


namespace App\Security;

use App\Service\EncryptionService;
use Lexik\Bundle\JWTAuthenticationBundle\Encoder\LcobucciJWTEncoder;
use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTDecodeFailureException;
use Lexik\Bundle\JWTAuthenticationBundle\Exception\JWTEncodeFailureException;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWSProvider\JWSProviderInterface;

class JwtCustomEncoder extends LcobucciJWTEncoder
{
    public function __construct(
        private readonly EncryptionService $encryptionService,
        JWSProviderInterface $jwsProvider
    ) {
        parent::__construct($jwsProvider);
    }

    public function encode(array $payload, array $header = [])
    {
        try {
            $token = parent::encode($payload, $header);

            return $this->encryptionService->encrypt($token);
        } catch (\Exception $e) {
            throw new JWTEncodeFailureException(JWTEncodeFailureException::INVALID_CONFIG, 'An error occurred while trying to encode the JWT token.', $e);
        }
    }

    public function decode($token): array
    {
        try {
            $decryptedToken = $this->encryptionService->decrypt($token);
            if (!$decryptedToken) {
                 throw new \RuntimeException('Token not encrypted');
            }

            return parent::decode($decryptedToken);
        } catch (\Exception $e) {
            throw new JWTDecodeFailureException(JWTDecodeFailureException::INVALID_TOKEN, 'Invalid JWT Token', $e);
        }
    }
}
@chalasr
Copy link
Collaborator

chalasr commented Dec 14, 2024

This contradicts with the bundle's design so I would not implement it in core. You would need to decorate JWTCookieProvider for your use case. You may also want to have a look at https://github.com/Spomky-Labs/lexik-jose-bridge instead of writing your own encryption.
Thanks

@chalasr chalasr closed this as completed Dec 14, 2024
@charlieandroid55
Copy link
Author

It's a shame. I understand what you're saying, but the idea is that I need to use my own encoder for security reasons, on top of the default one. In other words, there are two levels: the first level is that the token is encoded by encoder.lcobucci, and then I encrypt that hash with my algorithm. The issue is that the custom encoder is called for decoding when the configuration is via headers, but not when it's via cookies. Normally, cookies should also follow the same encoding and decoding logic as headers. It's because the cookies call a JWTSplitter instead of first calling the JWTCookieProvider. Since the JWTCookieProvider is not called, the JWTSplitter receives a hash that does not have the expected format. If it first called the JWTCookieProvider, it would decode the token correctly.

@chalasr chalasr reopened this Dec 19, 2024
@chalasr
Copy link
Collaborator

chalasr commented Dec 19, 2024

Can you create a simple application with the minimal code that allows reproducing the issue and share the repository here?

@charlieandroid55
Copy link
Author

Can you create a simple application with the minimal code that allows reproducing the issue and share the repository here?

Hello, sorry for the delay. Here is the repository If you need anything else, feel free to reach out to me. Additionally, I have included the Postman collection in case you need it. Thank you in advance!

@chalasr
Copy link
Collaborator

chalasr commented Dec 24, 2024

Thank you! I'm taking a break for Christmas but I'll look into this asap.

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

2 participants