Overview
Version 6.1 is a security and maintenance release. The main driver is an upstream security advisory in firebase/php-jwt that affects all v6 releases of that library. Upgrading to the patched version enforces a stricter minimum key size for HMAC algorithms, which requires all JWT_SECRET values to be regenerated in the correct format. Documentation has also been restructured and improved across the board.
Security Fix
firebase/php-jwt — PKSA-y2cr-5h3j-g3ys (CVE-2025-45769, published 2025-07-31)
firebase/php-jwt had a known security advisory (PKSA-y2cr-5h3j-g3ys / CVE-2025-45769, published 2025-07-31) affecting all v6 releases. This version upgrades byjg/jwt-wrapper to a release that depends on the patched firebase/php-jwt, eliminating the vulnerability.
byjg/jwt-wrapper to a release that depends on the patched firebase/php-jwt, eliminating the vulnerability.
As a side effect of the fix, the library now strictly enforces a minimum key size of 512 bits (64 bytes) for HS512 — the default algorithm used by this architecture. Short plain-text secrets that were silently accepted before will now throw a "Provided key is too short" exception at login time.
Action required: all environments must have their JWT_SECRET regenerated. See the upgrade path below.
Breaking Changes
| Before | After | Description |
|---|---|---|
JWT_SECRET=short-plain-text |
JWT_SECRET=<base64 of 64+ bytes> |
JWT_SECRET must now be a base64-encoded string whose decoded value is at least 64 bytes. Plain-text secrets are rejected at runtime. |
| Existing JWT tokens | Invalidated | All tokens signed with the old secret become invalid after the secret is rotated. Users will need to log in again. |
Changes
JWT Secret Format Requirement
JwtHashHmacSecret base64-decodes the JWT_SECRET value before using it as the signing key. The patched firebase/php-jwt now validates that the decoded key is at least 512 bits (64 bytes) for HS512. Secrets must be generated with:
APP_ENV=dev composer terminal
php> \ByJG\JwtWrapper\JwtWrapper::generateSecret(64)
# => 'OFbOmC2VxlgQHNrBLa/wyj7/fFkgPnLpckbXMVuIU7Sqb3RTztNx3xzEYaoeA31JUpvBjkD7FRKBFGQ0+fnTig=='Note:
php -rcannot be used directly because it does not load the project autoloader. Usecomposer terminalinstead.
The staging and prod credentials.env templates now ship with a placeholder that already satisfies the minimum size and include generation instructions as comments.
composer create-project (PostCreateScript) already calls JwtWrapper::generateSecret(64) to produce a fresh compliant secret for every environment during setup — no changes needed there.
Documentation
- Restructured documentation for improved clarity and navigation
- Updated all
JWT_SECRETexamples to use valid base64-encoded values - Corrected minimum key size references from "32 characters" to "64 decoded bytes"
- Replaced
php -rgeneration examples with the correctcomposer terminalcommand - Removed redundant links in advanced configuration documentation
- Updated README badge and license link
Upgrade Path from 6.0 to 6.1
Step 1: Update Dependencies
composer updateStep 2: Regenerate JWT_SECRET for Every Environment
Run the following once per environment and copy the output into the corresponding config/<env>/credentials.env:
APP_ENV=dev composer terminal
php> \ByJG\JwtWrapper\JwtWrapper::generateSecret(64)Update each file:
# config/dev/credentials.env
JWT_SECRET=<output from above>
# config/test/credentials.env
JWT_SECRET=<output from above>
# config/staging/credentials.env
JWT_SECRET=<output from above>
# config/prod/credentials.env
JWT_SECRET=<output from above>Generate a different secret for each environment. Never reuse the same secret across environments.
Step 3: Inform Users
All existing JWT tokens are invalidated once the secret is rotated. Users will receive a 401 on their next request and will need to log in again.
Step 4: Run Tests
composer testResources
Full Changelog: 6.0.0...6.1.0