medzuch/jwt-bundle
medzuch/jwt-bundle is a Symfony bundle for JWT authentication, offering configurable services to issue, validate, and handle JSON Web Tokens in PHP applications. It streamlines token-based auth setup and integration with Symfony's service container.
RefreshTokenStoreInterface is a shape your application implements, medzuch_jwt.refresh_token_generator mints the opaque value, and RefreshToken/RefreshTokenRecord are the pair the two exchange. Nothing in the package calls the interface — there is no entity, no migration, no default implementation. That is a legitimate choice, but it means the decision this release really supports is "do we standardise the contract and own the schema?" rather than "do we install refresh tokens?"consume() spends a token and reports a prior spend in a single call, because find() then delete() has a window and that window is exactly where a token gets used twice. For a PM this is a design constraint worth writing into the acceptance criteria: the store implementation must be one conditional write, not two statements.revokeGrant() ends one lineage — the reaction to a detected replay, where per RFC 9700 §4.14.2 the server cannot tell which party submitted the bad token, so it revokes rather than investigates. revokeAllFor() is the wider hammer for password change and "log out everywhere." These are two different user-facing flows with two different support burdens; having them named separately forces the product conversation about what a replay costs a user (they re-authorize).RefreshToken::hashOf() as the single home of the rule so the client-facing value and the stored hash cannot be handed in disagreeing. The fast-hash rationale is sound and worth adopting verbatim: the input is 256 bits from random_bytes(), and a slow hash on every refresh is a lever pointed at your own login flow.refresh_tokens: config key, both deliberate. Configuration-free is the right call given there is no persistence to configure — a key would advertise storage the package does not have. Roadmap implication: onboarding runs through jwt:key:generate plus the README quickstart, so documentation quality is a first-class dependency, not a nice-to-have.Medzuch\JwtBundle, medzuch_jwt.*, Flex/symfony/recipes-contrib), not a Laravel package. Nothing here is installable into a Laravel application as-is. The design — the contract, the single-call consume(), the two revocations, the hash rule — is portable, but the interfaces and service IDs are not. If the evaluation target is a Laravel codebase, the honest decision this release supports is "copy the semantics, not the dependency."Consider it when:
medzuch/jwt-bundle (library floor medzuch/jwt-php ^1.2.1). The upgrade is a constraint bump; configuration, options, and injected service shapes are unchanged, and applications that ignore the new namespace are unaffected.consume().Look elsewhere when:
For executives (one paragraph): This release is a low-risk, additive upgrade: no breaking changes, no configuration changes, no change to services already injected — upgrading is a version constraint bump. What we get for it is a standard, RFC-anchored way to describe the refresh half of a session across our Symfony applications, so two teams solving the same problem solve it the same way and security review has one shape to audit rather than several. The cost is not licence or integration; it is engineering time to implement and operate the token store, which stays in our schema by design. If our target is Laravel rather than Symfony, this package is not the vehicle — we would take the design and implement it ourselves.
For engineering (the actionable summary):
UPGRADE.md covers the rest.RefreshTokenStoreInterface. The one requirement that matters: consume() must be a single conditional write. Return null for a token the store never issued and for an empty presentation (a missing request parameter is then an invalid_grant, not an exception); return the record with alreadyUsed: true for one already spent.medzuch_jwt.refresh_token_generator; persist the SHA-256 from RefreshToken::hashOf(), never the raw value. Keep the fast hash — do not substitute password_hash().revokeGrant() to replay detection and revokeAllFor() to password change and log-out-everywhere. Pass the lifetime as an argument to generate(); it belongs to the flow, not the deployment.jwt:key:generate plus the README quickstart; there is no Flex recipe and there will not be one, so treat the quickstart as the integration spec and keep it tested.How can I help you explore Laravel packages today?