diff --git a/composer.json b/composer.json index 933fb4b2..997e9507 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,8 @@ "cakephp/cakephp": "^4.4", "cakephp/cakephp-codesniffer": "^4.0", "firebase/php-jwt": "^6.2", - "phpunit/phpunit": "^8.5 || ^9.3" + "phpunit/phpunit": "^8.5 || ^9.3", + "symfony/cache": "^5.4 || ^6.0" }, "suggest": { "cakephp/orm": "To use \"OrmResolver\" (Not needed separately if using full CakePHP framework).", diff --git a/src/Authenticator/JwtAuthenticator.php b/src/Authenticator/JwtAuthenticator.php index 6cf20f8b..4be0b006 100644 --- a/src/Authenticator/JwtAuthenticator.php +++ b/src/Authenticator/JwtAuthenticator.php @@ -18,14 +18,19 @@ use ArrayObject; use Authentication\Identifier\IdentifierInterface; +use Cake\Cache\Cache; +use Cake\Http\Client; use Cake\Utility\Security; use Exception; +use Firebase\JWT\CachedKeySet; use Firebase\JWT\JWK; use Firebase\JWT\JWT; use Firebase\JWT\Key; +use Laminas\Diactoros\RequestFactory; use Psr\Http\Message\ServerRequestInterface; use RuntimeException; use stdClass; +use Symfony\Component\Cache\Adapter\Psr16Adapter; class JwtAuthenticator extends TokenAuthenticator { @@ -41,6 +46,7 @@ class JwtAuthenticator extends TokenAuthenticator 'secretKey' => null, 'subjectKey' => IdentifierInterface::CREDENTIAL_JWT_SUBJECT, 'jwks' => null, + 'jwksCache' => null, ]; /** @@ -149,7 +155,18 @@ protected function decodeToken(string $token): ?object { $jsonWebKeySet = $this->getConfig('jwks'); if ($jsonWebKeySet) { - $keySet = JWK::parseKeySet($jsonWebKeySet); + $jsonWebKeySetCache = $this->getConfig('jwksCache'); + if ($jsonWebKeySetCache) { + $keySet = new CachedKeySet( + $jsonWebKeySet, + new Client(), + new RequestFactory(), + new Psr16Adapter(Cache::pool($jsonWebKeySetCache)), + 3000 + ); + } else { + $keySet = JWK::parseKeySet($jsonWebKeySet); + } return JWT::decode( $token,