From eea55978e8af52159b9624848a6151ae208800de Mon Sep 17 00:00:00 2001 From: michalsn Date: Tue, 3 Mar 2026 18:59:49 +0100 Subject: [PATCH 1/2] chore: upgrade firebase/php-jwt to v7 --- UPGRADING.md | 33 +++++++++++++++++++ composer.json | 2 +- .../Authentication/JWT/JWTManagerTest.php | 8 ++--- tests/_support/TestCase.php | 5 +++ 4 files changed, 43 insertions(+), 5 deletions(-) diff --git a/UPGRADING.md b/UPGRADING.md index d44b19991..9dfcbf9fd 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,5 +1,38 @@ # Upgrade Guide +## Version 1.2 to 1.3 + +### JWT: Minimum Key Length Now Enforced + +If you use the JWT authenticator with an HMAC algorithm (`HS256`, `HS384`, or +`HS512`), the underlying `firebase/php-jwt` library was upgraded to v7, which +now enforces minimum key lengths at runtime. + +| Algorithm | Minimum secret length | +|-----------|-----------------------| +| HS256 | 32 bytes (256 bits) | +| HS384 | 48 bytes (384 bits) | +| HS512 | 64 bytes (512 bits) | + +If your secret is too short, every JWT encode **and** decode call will throw a +`LogicException` with the message `Cannot encode/decode JWT: Provided key is too short`. + +To generate a valid secret, run: + +```console +php -r 'echo base64_encode(random_bytes(32));' +``` + +Then update `$keys` in **app/Config/AuthJWT.php**: + +```php +'secret' => '', +``` + +> [!NOTE] +> Existing tokens signed with the old short secret will become unverifiable once +> the secret is replaced. Users will need to re-authenticate to obtain new tokens. + ## Version 1.0.0-beta.8 to 1.0.0 ## Removed Deprecated Items diff --git a/composer.json b/composer.json index 38de6c14c..80c17fba2 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "codeigniter/phpstan-codeigniter": "^1.3", "codeigniter4/devkit": "^1.3", "codeigniter4/framework": ">=4.3.5 <4.5.0 || ^4.5.1", - "firebase/php-jwt": "^6.4", + "firebase/php-jwt": "^7.0.3", "mikey179/vfsstream": "^1.6.7", "mockery/mockery": "^1.0", "phpstan/phpstan-strict-rules": "^2.0" diff --git a/tests/Unit/Authentication/JWT/JWTManagerTest.php b/tests/Unit/Authentication/JWT/JWTManagerTest.php index 4197184cb..24e381775 100644 --- a/tests/Unit/Authentication/JWT/JWTManagerTest.php +++ b/tests/Unit/Authentication/JWT/JWTManagerTest.php @@ -273,7 +273,7 @@ public function testParseCanDecodeTokenSignedByOldKey(): void [ 'kid' => 'Key01', 'alg' => 'HS256', // algorithm. - 'secret' => 'Key01_Secret', + 'secret' => 'Key01_Secret_at_least_256_bits!!', ], ]; @@ -289,12 +289,12 @@ public function testParseCanDecodeTokenSignedByOldKey(): void [ 'kid' => 'Key02', 'alg' => 'HS256', // algorithm. - 'secret' => 'Key02_Secret', + 'secret' => 'Key02_Secret_at_least_256_bits!!', ], [ 'kid' => 'Key01', 'alg' => 'HS256', // algorithm. - 'secret' => 'Key01_Secret', + 'secret' => 'Key01_Secret_at_least_256_bits!!', ], ]; @@ -311,7 +311,7 @@ public function testParseCanSpecifyKey(): void [ 'kid' => 'Key01', 'alg' => 'HS256', // algorithm. - 'secret' => 'Key01_Secret', + 'secret' => 'Key01_Secret_at_least_256_bits!!', ], ]; diff --git a/tests/_support/TestCase.php b/tests/_support/TestCase.php index a7af822ea..25ea5d92a 100644 --- a/tests/_support/TestCase.php +++ b/tests/_support/TestCase.php @@ -51,5 +51,10 @@ protected function setUp(): void $config = config('Security'); $config->csrfProtection = 'session'; Factories::injectMock('config', 'Security', $config); + + // Set a valid JWT secret (≥ 256 bits for HS256) required by firebase/php-jwt v7 + $config = config('AuthJWT'); + $config->keys['default'][0]['secret'] = 'a-very-secure-secret-key-for-hs256-ok'; + Factories::injectMock('config', 'AuthJWT', $config); } } From 7b6c44f1d4572ec3a6209cfc7d08c41a9408bcd5 Mon Sep 17 00:00:00 2001 From: michalsn Date: Tue, 3 Mar 2026 19:27:27 +0100 Subject: [PATCH 2/2] upgrading --- UPGRADING.md | 18 ++++++------------ src/Config/AuthJWT.php | 2 +- tests/_support/TestCase.php | 2 +- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/UPGRADING.md b/UPGRADING.md index 9dfcbf9fd..f7827a81c 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -8,22 +8,16 @@ If you use the JWT authenticator with an HMAC algorithm (`HS256`, `HS384`, or `HS512`), the underlying `firebase/php-jwt` library was upgraded to v7, which now enforces minimum key lengths at runtime. -| Algorithm | Minimum secret length | -|-----------|-----------------------| -| HS256 | 32 bytes (256 bits) | -| HS384 | 48 bytes (384 bits) | -| HS512 | 64 bytes (512 bits) | +| Algorithm | Minimum secret length | Command to generate | +|-----------|-----------------------|---------------------------------------------------| +| HS256 | 32 bytes (256 bits) | `php -r 'echo base64_encode(random_bytes(32));'` | +| HS384 | 48 bytes (384 bits) | `php -r 'echo base64_encode(random_bytes(48));'` | +| HS512 | 64 bytes (512 bits) | `php -r 'echo base64_encode(random_bytes(64));'` | If your secret is too short, every JWT encode **and** decode call will throw a `LogicException` with the message `Cannot encode/decode JWT: Provided key is too short`. -To generate a valid secret, run: - -```console -php -r 'echo base64_encode(random_bytes(32));' -``` - -Then update `$keys` in **app/Config/AuthJWT.php**: +Run the command for your algorithm, then update `$keys` in **app/Config/AuthJWT.php**: ```php 'secret' => '', diff --git a/src/Config/AuthJWT.php b/src/Config/AuthJWT.php index b0ca11e8a..1aa0c9c1e 100644 --- a/src/Config/AuthJWT.php +++ b/src/Config/AuthJWT.php @@ -58,7 +58,7 @@ class AuthJWT extends BaseConfig [ 'kid' => '', // Key ID. Optional if you have only one key. 'alg' => 'HS256', // algorithm. - // Set secret random string. Needs at least 256 bits for HS256 algorithm. + // Set secret random string. Needs at least 256/384/512 bits for HS256/HS384/HS512. // E.g., $ php -r 'echo base64_encode(random_bytes(32));' 'secret' => '', ], diff --git a/tests/_support/TestCase.php b/tests/_support/TestCase.php index 25ea5d92a..7f37a087e 100644 --- a/tests/_support/TestCase.php +++ b/tests/_support/TestCase.php @@ -52,7 +52,7 @@ protected function setUp(): void $config->csrfProtection = 'session'; Factories::injectMock('config', 'Security', $config); - // Set a valid JWT secret (≥ 256 bits for HS256) required by firebase/php-jwt v7 + // Set a valid JWT secret (>= 256 bits for HS256) required by firebase/php-jwt v7 $config = config('AuthJWT'); $config->keys['default'][0]['secret'] = 'a-very-secure-secret-key-for-hs256-ok'; Factories::injectMock('config', 'AuthJWT', $config);