From 177773e51bcbb29e72552cbba4b7e6da10544c0a Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 25 Aug 2026 10:31:04 +0100 Subject: [PATCH 1/2] docs: state the real key types accepted on PHP 8 The constructor docblock still said 'string|resource', which predates PHP 8: openssl_pkey_get_private() now returns \OpenSSLAsymmetricKey, and validateKey() accepts the OpenSSL key/certificate objects while treating any string as a file:// path. The stale annotation makes static analyzers reject the correct object argument and steer callers toward passing PEM content as a string, which validateKey() can never accept (it fails with 'Invalid key: Should be resource of private key'). Exactly that caused utopia-php/vcs 5.2.4 to break GitHub App token generation in production (fixed in utopia-php/monorepo#160). Docblock/comment change only, no behavior change. Co-Authored-By: Claude Fable 5 --- src/JWT.php | 8 ++++++-- src/ValidatesJWT.php | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/JWT.php b/src/JWT.php index 14f885f..36fc64d 100644 --- a/src/JWT.php +++ b/src/JWT.php @@ -48,7 +48,7 @@ class JWT 'RS512' => \OPENSSL_ALGO_SHA512, ]; - /** @var string|resource The signature key. */ + /** @var string|resource|\OpenSSLAsymmetricKey|\OpenSSLCertificate|\OpenSSLCertificateSigningRequest The signature key. */ protected $key; /** @var array The list of supported keys with id. */ @@ -72,7 +72,11 @@ class JWT /** * Constructor. * - * @param string|resource $key The signature key. For RS* it should be file path or resource of private key. + * @param string|resource|\OpenSSLAsymmetricKey|\OpenSSLCertificate|\OpenSSLCertificateSigningRequest $key + * The signature key. For HS* it is the shared secret string. For RS* it should be + * the parsed private key (\OpenSSLAsymmetricKey on PHP 8+, resource on PHP 7) or a + * file path to it — a string is always treated as a file path, so passing PEM + * content directly is not supported. * @param string $algo The algorithm to sign/verify the token. * @param int $maxAge The TTL of token to be used to determine expiry if `iat` claim is present. * This is also used to provide default `exp` claim in case it is missing. diff --git a/src/ValidatesJWT.php b/src/ValidatesJWT.php index adfae8e..8fc2430 100644 --- a/src/ValidatesJWT.php +++ b/src/ValidatesJWT.php @@ -102,7 +102,8 @@ protected function validateTimestamps(array $payload) } /** - * Throw up if key is not resource or file path to private key. + * Throw up if key is not a private key instance (resource on PHP 7, \OpenSSLAsymmetricKey + * etc on PHP 8+) or a file path to one. A string is treated as a file path, never as PEM content. */ protected function validateKey() { From f3f077dda15722a1034a644003314b01be8a8ffc Mon Sep 17 00:00:00 2001 From: loks0n <22452787+loks0n@users.noreply.github.com> Date: Tue, 25 Aug 2026 10:36:31 +0100 Subject: [PATCH 2/2] style: align phpdoc columns for the widened key docblock Co-Authored-By: Claude Fable 5 --- src/JWT.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/JWT.php b/src/JWT.php index 36fc64d..1a509c7 100644 --- a/src/JWT.php +++ b/src/JWT.php @@ -72,16 +72,16 @@ class JWT /** * Constructor. * - * @param string|resource|\OpenSSLAsymmetricKey|\OpenSSLCertificate|\OpenSSLCertificateSigningRequest $key - * The signature key. For HS* it is the shared secret string. For RS* it should be - * the parsed private key (\OpenSSLAsymmetricKey on PHP 8+, resource on PHP 7) or a - * file path to it — a string is always treated as a file path, so passing PEM - * content directly is not supported. - * @param string $algo The algorithm to sign/verify the token. - * @param int $maxAge The TTL of token to be used to determine expiry if `iat` claim is present. - * This is also used to provide default `exp` claim in case it is missing. - * @param int $leeway Leeway for clock skew. Shouldnot be more than 2 minutes (120s). - * @param string $pass The passphrase (only for RS* algos). + * @param string|resource|\OpenSSLAsymmetricKey $key The signature key. For HS* it is the shared secret string. + * For RS* it should be the parsed private key + * (\OpenSSLAsymmetricKey on PHP 8+, resource on PHP 7) or a + * file path to it. A string is always treated as a file + * path, never as PEM content. + * @param string $algo The algorithm to sign/verify the token. + * @param int $maxAge The TTL of token to be used to determine expiry if `iat` claim is present. + * This is also used to provide default `exp` claim in case it is missing. + * @param int $leeway Leeway for clock skew. Shouldnot be more than 2 minutes (120s). + * @param string $pass The passphrase (only for RS* algos). */ public function __construct( $key,