diff --git a/src/JWT.php b/src/JWT.php index 5386b601..ec381695 100644 --- a/src/JWT.php +++ b/src/JWT.php @@ -195,24 +195,35 @@ public static function decode( * Converts and signs a PHP array into a JWT string. * * @param array $payload PHP array - * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. - * @param string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256', + * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate|Key $key The secret key. + * @param ?string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256', * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' * @param string $keyId * @param array $head An array with header elements to attach * * @return string A signed JWT * + * @throws InvalidArgumentException + * * @uses jsonEncode * @uses urlsafeB64Encode */ public static function encode( array $payload, $key, - string $alg, + ?string $alg = null, ?string $keyId = null, ?array $head = null ): string { + if ($key instanceof Key) { + if ($alg !== null) { + throw new InvalidArgumentException('If key is instance of Key alg must be null'); + } + $alg = $key->getAlgorithm(); + $key = $key->getKeyMaterial(); + } elseif ($alg === null) { + throw new InvalidArgumentException('alg cannot be null unless key is instance of Key'); + } $header = ['typ' => 'JWT']; if (isset($head)) { $header = \array_merge($header, $head); @@ -236,19 +247,29 @@ public static function encode( * Sign a string with a given key and algorithm. * * @param string $msg The message to sign - * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key. - * @param string $alg Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'ES256K', 'HS256', + * @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate|Key $key The secret key. + * @param ?string $alg Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'ES256K', 'HS256', * 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512' * * @return string An encrypted message * * @throws DomainException Unsupported algorithm or bad key was specified + * @throws InvalidArgumentException */ public static function sign( string $msg, $key, - string $alg + ?string $alg = null ): string { + if (is_a($key, Key::class)) { + if ($alg !== null) { + throw new InvalidArgumentException('If key is instance of Key alg must be null'); + } + $alg = $key->getAlgorithm(); + $key = $key->getKeyMaterial(); + } elseif ($alg === null) { + throw new InvalidArgumentException('alg cannot be null unless key is instance of Key'); + } if (empty(static::$supported_algs[$alg])) { throw new DomainException('Algorithm not supported'); } diff --git a/tests/JWTTest.php b/tests/JWTTest.php index 805b867a..db42274d 100644 --- a/tests/JWTTest.php +++ b/tests/JWTTest.php @@ -547,6 +547,29 @@ public function testAdditionalHeaderOverrides() $this->assertEquals('HS256', $headers->alg, 'alg param not overridden'); } + public function testNullAlgFails() + { + $this->expectException(InvalidArgumentException::class); + JWT::encode(['message' => 'abc'], 'my_key'); + } + + public function testEncodingWithKeyObject() + { + $payload = [ + 'message' => 'abc' + ]; + $key = new Key('my_key', 'HS256'); + $encoded = JWT::encode($payload, $key); + $decoded = JWT::decode($encoded, $key); + $this->assertSame($decoded->message, 'abc'); + } + + public function testNotNullAlgWhenUsingKeyObjectFails() + { + $this->expectException(InvalidArgumentException::class); + JWT::encode(['message' => 'abc'], new Key('my_key', 'HS256'), 'HS256'); + } + public function testDecodeExpectsIntegerIat() { $this->expectException(UnexpectedValueException::class);