diff --git a/src/JWT.php b/src/JWT.php index 843d0ae0..a8e274ba 100644 --- a/src/JWT.php +++ b/src/JWT.php @@ -68,12 +68,12 @@ class JWT /** * Decodes a JWT string into a PHP object. * - * @param string $jwt The JWT - * @param Key|array $keyOrKeyArray The Key or associative array of key IDs (kid) to Key objects. - * If the algorithm used is asymmetric, this is the public key - * Each Key object contains an algorithm and matching key. - * Supported algorithms are 'ES384','ES256', 'HS256', 'HS384', - * 'HS512', 'RS256', 'RS384', and 'RS512' + * @param string $jwt The JWT + * @param Key|array|string|resource $keyOrKeyArray The Key or associative array of key IDs (kid) to Key objects. + * If the algorithm used is asymmetric, this is the public key + * Each Key object contains an algorithm and matching key. + * Supported algorithms are 'ES384','ES256', 'HS256', 'HS384', + * 'HS512', 'RS256', 'RS384', and 'RS512' * * @return stdClass The JWT's payload as a PHP object * @@ -122,7 +122,7 @@ public static function decode( throw new UnexpectedValueException('Algorithm not supported'); } - $key = self::getKey($keyOrKeyArray, property_exists($header, 'kid') ? $header->kid : null); + $key = self::getOrCreateKeyInstance($keyOrKeyArray, $header); // Check the algorithm if (!self::constantTimeEquals($key->getAlgorithm(), $header->alg)) { @@ -621,4 +621,19 @@ private static function readDER(string $der, int $offset = 0): array return [$pos, $data]; } + + private static function getOrCreateKeyInstance(array|Key $keyOrKeyArray, mixed $header): Key + { + if ( + is_string($keyOrKeyArray) + || $keyOrKeyArray instanceof OpenSSLAsymmetricKey + || $keyOrKeyArray instanceof OpenSSLCertificate + || is_resource($keyOrKeyArray) + ) { + $key = new Key($keyOrKeyArray, $header->alg); + } else { + $key = self::getKey($keyOrKeyArray, property_exists($header, 'kid') ? $header->kid : null); + } + return $key; + } } diff --git a/tests/JWTTest.php b/tests/JWTTest.php index 8b23ad6b..ef12d53e 100644 --- a/tests/JWTTest.php +++ b/tests/JWTTest.php @@ -321,6 +321,21 @@ public function testRSEncodeDecodeWithPassphrase() $this->assertEquals($decoded, $expected); } + public function testDecodeWithoutKid() + { + $privateKeyFile = __DIR__ . '/data/ecdsa-private.pem'; + $publicKeyFile = __DIR__ . '/data/ecdsa-public.pem'; + $privateKey = file_get_contents($privateKeyFile); + $payload = ['foo' => 'bar']; + $encoded = JWT::encode($payload, $privateKey, 'ES256'); + + // Verify decoding succeeds + $publicKey = file_get_contents($publicKeyFile); + $decoded = JWT::decode($encoded, $publicKey); + + $this->assertEquals('bar', $decoded->foo); + } + /** * @runInSeparateProcess * @dataProvider provideEncodeDecode