medzuch / jwt-php
Standalone, RFC 7519 / 7797 / 8725-compliant JWT library for PHP 8.3 and 8.4. Framework-agnostic.
Requires
- php: ~8.3.0 || ~8.4.0
- ext-json: *
- ext-mbstring: *
- ext-openssl: *
- ext-sodium: *
- psr/clock: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.95
- infection/infection: ^0.29
- nikic/php-fuzzer: ^0.0.11
- nyholm/psr7: ^1.8
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^12.0
- psr/http-client: ^1.0
- psr/log: ^3.0
- psr/simple-cache: ^3.0
- roave/security-advisories: dev-latest
- symfony/http-client: ^7.3
Suggests
- psr/http-client: ^1.0 — required by RemoteJwksResolver to fetch a jwks_uri.
- psr/http-factory: ^1.0 — required by RemoteJwksResolver to build PSR-7 requests.
- psr/log: ^3.0 — required only to use the optional PSR-3 logging hooks.
- psr/simple-cache: ^3.0 — required by RemoteJwksResolver to cache a fetched JWK Set.
This package is auto-updated.
Last update: 2026-08-19 10:45:49 UTC
README
A standalone, modern JWT library for PHP 8.3 and 8.4, built strictly to:
- RFC 7519 — JSON Web Token
- RFC 7515 / 7516 / 7517 / 7518 — JWS, JWE, JWK, JWA (underlying JOSE)
- RFC 7797 — JWS Unencoded Payload Option (supported at the JWS layer; refused at the JWT layer per RFC 7519's update)
- RFC 8725 — JWT Best Current Practices (BCP 225)
Framework-agnostic by design. Symfony integration lives in the separate
medzuch/jwt-bundle package (in design; this library
also drops into a custom Symfony authenticator directly — see the cookbook).
Status
Stable — the public API is frozen as of v1.0.0. From 1.0.0 the library
follows Semantic Versioning strictly: no
incompatible changes to the documented public surface within the 1.x line. What
is and isn't covered is spelled out in
docs/04 — Public API Surface › Stability promise —
in short, everything that document lists (and everything reachable from it not
marked @internal). Runs on PHP 8.3 and 8.4; both are covered by CI.
Why another JWT library?
Most PHP JWT libraries predate RFC 8725 and still encourage alg-driven verification — the
root cause of the algorithm-confusion attacks the BCP exists to stop. This library:
- Refuses
alg:noneand algorithm switching by construction (caller declares an allowlist). - Binds every key to its algorithm (one key, one purpose — BCP §3.1).
- Treats
b64:falseas forbidden in JWTs (RFC 7519, updated by 7797). - Separates JWS, JWT, and Profile layers so that an application-level "access token" is a single type with a single validator, not a permissive bag of claims.
- Ships with explicit typing (
typenforcement,application/<x>+jwt). - Refuses unsafe defaults: no
jku/x5ufetching, no compression in JWE, no password-as-HMAC-key.
See docs/ for the full design, threat model, and per-RFC compliance notes.
Quickstart (Docker)
make build # build the PHP 8.3 dev image (one-time, ~30s) make up # start the container make install # composer install make test # run the suite make qa # CS + PHPStan level 9 + tests make qa-84 # the same gate on PHP 8.4 (second container)
The default dev image is the floor of the supported window (8.3), because that
is the version a change breaks by accident; make qa-84 covers the ceiling.
Or without Docker, assuming PHP 8.3 or 8.4 with ext-sodium, ext-openssl, ext-mbstring:
composer install composer qa
Documentation
- 01 — Architecture
- 02 — Threat Model
- 03 — RFC Compliance Matrix
- 04 — Public API Surface
- 05 — Phased Roadmap
- 06 — Development Environment
- 07 — Testing Strategy
- 08 — Coding Standards
- 09 — Symfony Bundle Plan
- 10 — Security Policy
- 11 — Glossary
- 12 — Decisions
- 13 — Cookbook
- 14 — Performance
Contributing
See CONTRIBUTING.md and docs/08-coding-standards.md.
Security
Security issues: do not open a public issue. See SECURITY.md.
License
MIT — see LICENSE.