Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Jwt Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Product Decisions This Supports

  • Build-vs-buy on the refresh-token half of the session. v1.2.0 is the "buy the vocabulary, build the store" decision made explicit: 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?"
  • Closing a specific, well-known bug class before it ships. 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.
  • Revocation semantics mapped to real product moments. 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).
  • Token format and hashing as a settled default. Opaque token, stored as SHA-256, with 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.
  • Onboarding/roadmap: no Flex recipe (DEC-9) and no 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.
  • Framework caveat that should be stated plainly: this is a Symfony bundle (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."

When to Consider This Package

Consider it when:

  • You are on Symfony and already using 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.
  • You have more than one Symfony application issuing sessions and you want them to spell refresh, rotation and revocation the same way. The stated purpose of the namespace is exactly this: consistency across apps, not features within one.
  • Your team is comfortable owning the schema — entity, migration, indexes, retention/cleanup, and the atomic conditional write behind consume().
  • You want a reviewed, RFC-anchored contract to implement against instead of designing one in a ticket thread, and you value that the hard cases (double-spend, replay-vs-retry, revoke-one vs revoke-all) are already named.
  • You want no configuration surface — nothing to tune, nothing to drift.

Look elsewhere when:

  • You are on Laravel. There is no Laravel integration here and none is planned in this release. Porting the interface by hand is possible but you get no service wiring, no generator binding, and no upgrade path.
  • You want batteries included. If the team expects refresh tokens to work on install — shipped entity, migration, rotation and cleanup out of the box — this package will read as incomplete. It is a vocabulary release, and the release notes say so without apology.
  • You cannot take on schema ownership or the operational work of a token table (indexes on hash, expiry sweeps, per-subject revocation queries).
  • You need a recipe or managed config as part of your onboarding standard. DEC-9 confirms there will not be one.
  • Your scope is a single small app where a dozen lines of application code would do; the abstraction earns its keep across apps and teams, not within one.

How to Pitch It (Stakeholders)

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 by moving the constraint; nothing to configure. UPGRADE.md covers the rest.
  • Implement 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.
  • Mint via 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().
  • Wire 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.
  • Product/UX note to carry into design: a retry after a lost response is indistinguishable from a theft, and the documented outcome is that the client re-authorizes. Make sure that path is a reasonable experience, not a support ticket.
  • Onboarding is 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.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource