web-token/jwt-framework
A comprehensive PHP library for JSON Web Tokens, implementing JWS, JWE, JWK, JWT, and related RFCs. It offers signing, encryption, key management, and token validation with a clean, standards-compliant API suitable for any PHP project.
Architecture fit. web-token/jwt-framework is a comprehensive, standards-first implementation of the JOSE stack — JWS, JWE, JWK/JWKS, JWA and JWT (RFC 7515–7519), plus JSON serialization, nested JWTs, key wrapping (RSA-OAEP, AES-GCM, ECDH-ES, PBES2) and a wide algorithm matrix (HS*, RS*, PS*, ES*, EdDSA). That is materially more than Laravel teams normally need for session/API auth, but it is exactly the right shape for OIDC relying-party work, machine-to-machine credentials, encrypted claims, third-party JWKS verification, or any FAPI-adjacent requirement. Critically, jwt-framework is an aggregate package that pulls in the Symfony bundle and console tooling. On a Laravel stack the correct artifact is the standalone web-token/jwt-library; consuming the full framework drags Symfony components into a stack that already has its own container, config and console.
Integration feasibility. There is no first-party Laravel service provider, so this is a "library plus thin glue" integration, not a drop-in. The glue is modest: one service provider, one config file for key material and algorithm allowlists, and a small wrapper service exposing sign() / verify() / decrypt(). The library's dependencies are PSR-friendly (psr/cache v2–v3, PSR-18 HTTP clients, brick/math), and both Laravel's cache repository and Guzzle satisfy those contracts, so JWKS caching and remote key-set fetching fit the existing stack without new infrastructure. The absence of a Laravel-native package means we own the binding code and its upgrade surface — a real but bounded cost.
Technical risk. The dominant risk is configuration, not code quality. JOSE libraries fail open in predictable ways when misused: alg: none acceptance, algorithm confusion between HMAC and RSA public keys, kid lookups that silently fall back to the first key in a set, unbounded JWKS cache staleness, and clock-skew handling left to defaults. The library gives correct primitives but expects the integrator to be strict. Secondary risks: a single primary maintainer (@Spomky) is the bus factor for a cryptographic dependency — mitigated by MIT licensing, good test coverage and an explicit private security-disclosure channel, but not eliminated; and unusually fast branch proliferation (3.4.x, 4.0.x, 4.1.x, 4.2.x all receiving patches simultaneously, with deprecations such as UrlKeySetFactory::enabledCache() and refactored constructor signatures between minors). Any team that pins loosely will absorb breaking changes. Note that the supplied metadata (0 dependents, README-only docs) understates the package — Packagist and the dedicated documentation site at web-token.spomky-labs.com tell a healthier story, so the 37.7 score should be read as a metadata artifact, not a quality verdict.
Key questions to resolve before adoption.
p2c bounding fix suggests fixes land forward-first)?jwt-library alone a supported, tested consumption mode, or is it optimized for the Symfony bundle?Stack fit. Laravel already ships three token models: Sanctum (opaque), Passport (OAuth2 via league/oauth2-server on lcobucci/jwt), and hand-rolled signed tokens. web-token should be introduced for a specific capability those do not cover — JWE-encrypted payloads, JWKS-based verification of tokens issued elsewhere, EdDSA, or strict multi-algorithm negotiation — rather than as a wholesale replacement. If the requirement is simple first-party API tokens, Sanctum is cheaper and this package is over-engineering. If the requirement is full OAuth2 authorization-server behaviour, Passport remains the better fit and running both JWT stacks in one application should be avoided.
Target architecture. Install web-token/jwt-library only. Wrap it in App\Crypto\JwtService (sign/verify/encrypt/decrypt) behind an interface so the underlying implementation stays swappable. Register keys through a config/jwt.php plus a key resolver backed by environment/KMS references — never key files committed to the repo. Bind Psr\Cache\CacheItemPoolInterface to Laravel's cache store for JWKS caching, and Psr\Http\Client\ClientInterface to Guzzle for remote key-set retrieval. Enforce a hard algorithm allowlist in config and reject anything not on it at the service boundary, not in controllers.
Migration path. If replacing an existing JWT implementation, run dual-verification first: the new service verifies tokens, the old one continues to issue, and only after verification parity is proven does issuance cut over. This gives a clean rollback point and avoids a forced mass re-issue of credentials — which, for long-lived tokens, is the single most disruptive part of any JWT migration.
Compatibility. PHP 8.2+ is the floor in the 4.x line, with active work on 8.4/8.5 deprecations and Symfony 8 support — good forward hygiene, and compatible with current Laravel releases. The main incompatibility to check is PSR cache version pinning if other packages in the app constrain psr/cache, and any transitive brick/math version conflict with payment or money libraries.
Sequencing.
kid-based resolution, clock-skew policy.alg and unknown-kid tokens.Maintenance. Budget for continuous patch tracking: this project ships frequent patch releases across multiple maintained branches, and security-relevant fixes (PBES2 iteration bounding, base64/OpenSSL error handling, Ed25519 corrections) are routine. That is a good sign for a crypto dependency, but it means automated dependency updates plus a review gate, not "set and forget." Because Laravel integration is bespoke, every minor upgrade may require touching our wrapper — keep that wrapper thin and well-tested.
Support. No commercial SLA; support flows through GitHub issues, a sponsor/Patreon channel that influences prioritization, and a private security email. Plan for self-sufficiency: the team must be able to read the library's source and the JOSE RFCs. Escalation to the maintainer should be treated as best-effort.
Scaling. Signature verification is cheap and horizontally scalable; JWE decryption and key unwrapping are more expensive per request, so if encrypted tokens are on the hot path, benchmark early and cache parsed key objects in-process rather than re-parsing JWKs per request. Remote JWKS fetching must be cached with a sane TTL and a stale-while-revalidate fallback — an uncached JWKS call in the auth path turns the identity provider into a hard dependency and a latency amplifier. Key generation and rotation should run as queued/console jobs, never inline with a web request.
Failure modes to instrument. Algorithm confusion or none acceptance (catastrophic, prevent by allowlist); unknown kid after a rotation where the verifier's key set lags the issuer's (causes 401 storms — alert on kid mismatch rate); clock skew producing spurious expiry failures across hosts; JWKS cache stampede or stale cache after IdP key rollover; OpenSSL/ext-sodium absence in a container image causing runtime failures only in one environment; and library exceptions (InvalidArgumentException and friends) escaping uncaught into 500s instead of clean 401s.
Ramp-up. A mid-level Laravel engineer can produce a working sign/verify path in one to two days. Production confidence — rotation, JWKS, strict algorithm policy, negative-path tests, runbooks — is a two-to-three week effort for one engineer, plus review time from someone with cryptographic literacy. The documentation site is solid but Symfony-oriented, so expect to translate bundle-centric examples into Laravel idioms. Recommended guardrails: a short internal design note fixing the allowed algorithms and key lifecycle, a rotation rehearsal in staging, and a standing rule that no JOSE configuration lives outside the single config file and service class.
Verdict. Adopt selectively, for standards-heavy token requirements, via jwt-library rather than the full framework, with a thin owned wrapper and disciplined patch tracking. Reject for simple first-party API authentication, where Sanctum or Passport is lower total cost.
How can I help you explore Laravel packages today?