Refactor JWT into a Hypervel-native auth package#405
Conversation
Document the researched JWT refactor plan before the implementation commits. The plan records why the package should keep Hypervel's array-based, coroutine-safe architecture instead of restoring the upstream mutable object graph. It also captures the signed-off decisions for claim construction, parsing, middleware, console commands, validation, guard behavior, provider wiring, docs, and tests so the implementation has a durable reference.
Add the contracts needed for the Hypervel-native JWT surface. This introduces optional JWTSubject support for model-controlled subject identifiers and custom claims, TemporalValidation so refresh can intentionally skip time-window checks, TokenExtractor for the parser chain, and a SecretMissingException for fail-fast signing configuration errors. The existing manager and validation contracts are widened to expose the new encode/decode/refresh behavior without bringing back the upstream mutable object model.
Modernize JWT claim validation around the native array payload model. Expired and issued-at validation now participate in the TemporalValidation contract so refresh can bypass only time-window checks while still enforcing structural and issuer checks. Add issuer validation, replace the misspelled NotBeforeCliam class and test with NotBeforeClaim, and cover the corrected validation behavior with dedicated tests.
Add an array-based ClaimFactory that builds issue and refresh claims without restoring upstream claim objects. The factory owns subject identifiers, model locking hashes, issuer stamping, standard temporal claims, custom claims, and refresh claim persistence. Static model-hash caching is limited to immutable class metadata and is reset through AfterEachTestSubscriber so tests do not leak worker-lifetime state.
Add Hypervel-native token extractors for authorization headers, cookies, and request input. The parser chain stays stateless and singleton-safe: extractors read from the current request only when invoked and do not store token state on worker-lifetime services. Parser tests cover extractor order, bearer parsing, cookie parsing, input parsing, and missing-token behavior.
Add JWT middleware for authenticating requests and refreshing tokens in responses. The middleware delegates token parsing and guard behavior to the existing JWT services, keeps no mutable request state of its own, and only catches expected authentication/token failures. Tests cover successful authentication, token renewal, refresh responses, missing tokens, and invalid-token failure paths.
Add the jwt:secret console command for generating and writing symmetric JWT secrets. The command supports show, force, confirmation, and non-interactive skip flows. Tests isolate .env mutation with useEnvironmentPath() and ParallelTesting::tempDir(), matching the existing key generation precedent so environment writes do not leak across the worker's Testbench skeleton clone.
Add jwt:generate-certs for RSA and EC signing key generation. The command writes certificate paths and algorithm settings into the configured environment file, supports encrypted and unencrypted private keys, refuses accidental overwrites without force, and fails before writing certificates when the environment file is missing. Tests cover RSA, EC, passphrase handling, overwrite protection, invalid algorithms, and isolated output cleanup.
Update JWTManager around the native claim factory and array payload model. The manager now owns blacklist jti stamping for direct encode calls, supports decode-for-refresh validation rules, preserves persistent claims correctly during refresh, handles idempotent invalidation, and exposes the expanded facade surface. Tests cover encode, decode, refresh, blacklist, persistent-claim, and invalidation behavior so the token lifecycle stays consistent across guard and direct manager usage.
Tighten the Lcobucci provider around signing configuration and claim validation. The provider now fails clearly when signing material is missing, handles symmetric and asymmetric algorithms through the configured keys, supports the new validation contract flow, and keeps decode behavior compatible with refresh-time temporal skipping. Tests cover missing secrets, configured secrets, key file usage, claim validation, and refresh validation paths.
Refactor JwtGuard around coroutine-scoped authentication state and the native claim factory. The guard now keeps token, payload, user, ttl, custom claims, and last-attempted state isolated per coroutine, fixes attempt/once/onceUsingId semantics, resets one-shot custom claims after token creation, supports subject locking, and dispatches auth events only when listeners are registered. Tests cover the corrected API behavior, event dispatch guards, subject/provider matching, and coroutine isolation so auth state cannot bleed between concurrent requests.
Update JWT package wiring for the new native services and defaults. The service provider now registers the claim factory, parser chain, console commands, manager, guard integration, middleware aliases, and package services explicitly. The config and environment examples expose the new token, issuer, blacklist, parser, and key options, while default validation enables required claims, expiration, issuer, issued-at, and not-before checks. Tests verify package discovery metadata, service bindings, config shape, parser defaults, and the corrected NotBeforeClaim class name.
Add full Boost documentation for Hypervel's JWT package and link it from the docs index and authentication guide. The new JWT guide covers installation, guard setup, token issuing, refresh and invalidation, middleware, token extraction, custom claims, subject locking, issuer validation, blacklist behavior, key generation, asymmetric signing, configuration, and testing notes in the style of the existing Boost docs. The package README stays concise and points readers to the full framework documentation.
Remove JWT application configuration from the components root .env.example. That file documents local integration-test environment variables for framework development, not application-level skeleton configuration. JWT defaults remain in the Testbench skeleton env example where application-style config belongs.
Document the JWT_DRIVER and JWT_ISSUER environment-backed config options in the Boost JWT guide. JWT_DRIVER belongs with the signing provider configuration, and JWT_ISSUER belongs with issuer validation so every env-backed JWT option exposed by the package config is represented in the user-facing documentation.
📝 WalkthroughWalkthroughImplements a Hypervel-native JWT refactor: introduces ChangesJWT Hypervel-native parity refactor
Sequence Diagram(s)sequenceDiagram
participant Client
participant JwtGuard
participant Parser
participant ClaimFactory
participant JWTManager
participant Dispatcher
Client->>JwtGuard: attempt(credentials, login=true)
JwtGuard->>Dispatcher: dispatch Attempting
JwtGuard->>JwtGuard: retrieveByCredentials + validateCredentials
alt valid credentials
JwtGuard->>Dispatcher: dispatch Validated
JwtGuard->>ClaimFactory: make(user, provider, ttl, customClaims)
ClaimFactory-->>JwtGuard: claims array with sub/prv/iat/exp
JwtGuard->>JWTManager: encode(claims)
JWTManager-->>JwtGuard: JWT string
JwtGuard->>Dispatcher: dispatch Authenticated + Login
JwtGuard-->>Client: JWT string
else invalid
JwtGuard->>Dispatcher: dispatch Failed
JwtGuard-->>Client: false
end
Client->>JwtGuard: refresh(forceForever, resetClaims)
JwtGuard->>JWTManager: refresh(token, forceForever, resetClaims, customClaims, ttl)
JWTManager->>JWTManager: decodeForRefresh — skip TemporalValidation validators
JWTManager->>ClaimFactory: refresh(oldPayload, ttl, refreshIssuedAt, resetClaims, persistentClaims)
ClaimFactory-->>JWTManager: refreshed claims
JWTManager-->>JwtGuard: new JWT string
JwtGuard-->>Client: new JWT string
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThis PR completes the JWT package with a large set of previously-missing features while adapting the implementation for Hypervel's long-lived Swoole workers. All per-request mutable guard state (token, user, payload, TTL, custom claims) is moved into
Confidence Score: 5/5The new coroutine-scoped guard and claim-factory logic is well-structured and the ordering of context operations is correct throughout; the two comments are upgrade-path notes rather than runtime defects. The core authentication flow (issue, decode, refresh, invalidate, logout) is implemented correctly with proper cleanup ordering. The two findings are both deployment-time concerns for applications upgrading from the previous JWT version rather than defects in the new code itself. No logic errors, race conditions, or security holes were found in the changed paths. src/jwt/src/ClaimFactory.php and src/jwt/config/jwt.php warrant attention for any team upgrading an existing deployment that has live JWT tokens, as the subject-lock default and the newly-enabled expiry validations together can silently invalidate those tokens on upgrade. Important Files Changed
Reviews (3): Last reviewed commit: "refactor(jwt): remove sliding refresh mi..." | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 9
🧹 Nitpick comments (3)
src/jwt/src/ClaimFactory.php (1)
158-163: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMark
flushState()as boot-or-tests-only.This public static mutator clears worker-lifetime cached state, so its docblock should explicitly warn callers not to use it in normal request flow. As per coding guidelines, "Add boot-only, tests-only, or boot-or-tests-only warning docblock text to public mutators that change worker-lifetime state when the method is intended only for boot-time configuration or tests."
♻️ Proposed docblock update
/** * Flush all static state. + * + * Warning: boot-or-tests-only. This mutates worker-lifetime cached state. */ public static function flushState(): void🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/jwt/src/ClaimFactory.php` around lines 158 - 163, Update the ClaimFactory::flushState() docblock to clearly mark it as boot-or-tests-only, since this public static mutator clears worker-lifetime cached state and should not be used during normal request flow. Add the required warning text directly above flushState() so callers are guided to use it only during boot-time configuration or tests.Source: Coding guidelines
src/jwt/src/JwtGuard.php (2)
92-99: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winUse the request from
RequestContextdirectly.Line 94 verifies coroutine request state, but Line 98 resolves
requestthrough the container, which depends on that binding being fresh/scoped. PassingRequestContext::get()removes the worker-lifetime binding ambiguity.Suggested change
- return $this->parser->parseToken($this->app->make('request')); + return $this->parser->parseToken(RequestContext::get());As per coding guidelines, “audit
make()calls for freshness versus auto-singleton behavior.” <coding_guidelines>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/jwt/src/JwtGuard.php` around lines 92 - 99, In JwtGuard::parseToken, the request is being resolved from the container even after RequestContext::has() confirms coroutine state, which can introduce stale worker-scoped bindings. Update parseToken to use the request instance from RequestContext::get() directly and pass that into parser->parseToken(), keeping the RequestContext check as the guard and removing the app->make('request') dependency.Source: Coding guidelines
439-460: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd boot-only warnings to worker-lifetime mutators.
attempting()registers listeners on the dispatcher andsetDispatcher()swaps the guard dispatcher; both mutate worker-lifetime state and should say they are boot/tests-only.Suggested docblock updates
/** * Register an authentication attempt event listener. + * + * Boot-only. Listener registrations persist on the worker-lifetime dispatcher. */ public function attempting(callable $callback): void @@ /** * Set the event dispatcher instance. + * + * Boot or tests only. The dispatcher is stored on the worker-lifetime guard. */ public function setDispatcher(Dispatcher $events): voidAs per coding guidelines, “Add boot-only, tests-only, or boot-or-tests-only warning docblock text to public mutators that change worker-lifetime state.” <coding_guidelines>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/jwt/src/JwtGuard.php` around lines 439 - 460, Update the public mutators in JwtGuard—especially attempting() and setDispatcher()—to include the required boot-only / tests-only warning docblock text. These methods register event listeners and replace the dispatcher, so their PHPDoc should clearly mark them as boot/tests-only worker-lifetime state changes per the coding guidelines. Keep the existing method behavior unchanged and adjust the docblocks near attempting(), getDispatcher(), and setDispatcher() as needed to match the project’s warning wording.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/jwt/config/jwt.php`:
- Around line 269-274: Make input-based JWT parsing opt-in by removing
Hypervel\JWT\Http\Parser\InputSource from the default parser chain in jwt config
while keeping Hypervel\JWT\Http\Parser\AuthHeaders as the secure default. Update
the jwt.php parser configuration so only header-based parsing is enabled by
default, and provide a clear way for apps to add InputSource explicitly when
they want to accept token input. Also review any related parser registration
logic in InputSource to ensure no other default path enables request-input
tokens implicitly.
In `@src/jwt/src/Console/JwtGenerateCertsCommand.php`:
- Around line 96-108: The key generation flow in
JwtGenerateCertsCommand::generate should not update the environment file until
both key writes succeed and the private key is secured. Check the return value
of file_put_contents for both the private key and public key, throw a
RuntimeException if either write fails, and explicitly set restrictive
permissions on the private key after writing it instead of relying on the
process umask. Only call Env::writeVariables once the key files are successfully
created and protected.
- Around line 39-76: The EC branch in JwtGenerateCertsCommand currently allows
mismatched ES algorithm and curve settings, so align the chosen `--sha` with the
curve used when building the OpenSSL options. Update the logic around the `match
($algorithm)` and the EC `curve_name` assignment to either validate and reject
invalid `--sha`/`--curve` combinations or automatically map `ES256`, `ES384`,
and `ES512` to their required curves in `JwtGenerateCertsCommand`.
In `@src/jwt/src/Http/Parser/AuthHeaders.php`:
- Around line 25-33: The auth header parsing in AuthHeaders::parseBearerToken is
too permissive because it uses strripos to find any occurrence of Bearer
anywhere in the header. Update the matching logic to only accept a
comma-delimited header segment that actually starts with the Bearer scheme, then
extract the token from that exact segment and keep the existing trimming/null
behavior.
In `@src/jwt/src/JwtGuard.php`:
- Around line 432-435: forgetUser() currently only clears the token-specific
user context, so a previously cached default user can still reappear after
setToken() or logout(). Update JwtGuard::forgetUser() to also clear the default
user cache key used by getUserContextKey()/user.default, and make sure the
cleanup covers both the active token context and the fallback default context.
- Around line 268-273: The JwtGuard::claims method currently allows reserved
identity claims like sub and prv to be merged into the pending claims context,
which can override the subject/provider-lock values used by ClaimFactory::make()
for the next token. Add a guard in JwtGuard::claims (or centrally in
ClaimFactory::make) to reject or strip reserved claims before storing them in
CoroutineContext, while still allowing non-reserved custom claims to merge
normally.
In `@src/jwt/src/JWTManager.php`:
- Around line 147-151: In JWTManager::refresh, the replacement token is being
invalidated too early, before the new token is successfully created. Update the
flow so encode($claims) happens first, then call invalidate($token,
$forceForever) only after encoding succeeds, and keep the blacklistEnabled check
around that invalidation step. This ensures the old token is only blacklisted if
a replacement token is actually available.
- Around line 138-145: Reject reserved JWT/subject-lock claims before refresh by
validating the custom claim set passed through JWTManager::refresh() into
ClaimFactory::refresh(). Ensure claims like exp, nbf, iss, and jti cannot be
reintroduced via customClaims after managed claims are stripped, ideally by
adding a central guard in ClaimFactory and/or filtering before the refresh call.
Use the existing claim-handling flow in JWTManager and ClaimFactory as the place
to enforce this consistently.
In `@src/jwt/src/Validations/NotBeforeClaim.php`:
- Line 11: The `NotBeforeClaim` marker is causing
`JWTManager::decodeForRefresh()` to skip `nbf`, which lets `refresh()` accept
tokens before they are active. Update the refresh path so `nbf` is still
validated during refresh, either by removing `TemporalValidation` from
`NotBeforeClaim` or by special-casing `JWTManager::decodeForRefresh()` to keep
`NotBeforeClaim` enabled. Also verify `ClaimFactory::refresh()` preserves the
original `nbf` instead of restamping it to now.
---
Nitpick comments:
In `@src/jwt/src/ClaimFactory.php`:
- Around line 158-163: Update the ClaimFactory::flushState() docblock to clearly
mark it as boot-or-tests-only, since this public static mutator clears
worker-lifetime cached state and should not be used during normal request flow.
Add the required warning text directly above flushState() so callers are guided
to use it only during boot-time configuration or tests.
In `@src/jwt/src/JwtGuard.php`:
- Around line 92-99: In JwtGuard::parseToken, the request is being resolved from
the container even after RequestContext::has() confirms coroutine state, which
can introduce stale worker-scoped bindings. Update parseToken to use the request
instance from RequestContext::get() directly and pass that into
parser->parseToken(), keeping the RequestContext check as the guard and removing
the app->make('request') dependency.
- Around line 439-460: Update the public mutators in JwtGuard—especially
attempting() and setDispatcher()—to include the required boot-only / tests-only
warning docblock text. These methods register event listeners and replace the
dispatcher, so their PHPDoc should clearly mark them as boot/tests-only
worker-lifetime state changes per the coding guidelines. Keep the existing
method behavior unchanged and adjust the docblocks near attempting(),
getDispatcher(), and setDispatcher() as needed to match the project’s warning
wording.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: ae75aad8-d487-4d36-afd7-5fd1494a1909
📒 Files selected for processing (49)
docs/plans/2026-06-28-0709-jwt-hypervel-native-parity-refactor.mdsrc/boost/docs/authentication.mdsrc/boost/docs/documentation.mdsrc/boost/docs/jwt.mdsrc/jwt/README.mdsrc/jwt/composer.jsonsrc/jwt/config/jwt.phpsrc/jwt/src/ClaimFactory.phpsrc/jwt/src/Console/JwtGenerateCertsCommand.phpsrc/jwt/src/Console/JwtSecretCommand.phpsrc/jwt/src/Contracts/JWTSubject.phpsrc/jwt/src/Contracts/ManagerContract.phpsrc/jwt/src/Contracts/TemporalValidation.phpsrc/jwt/src/Contracts/TokenExtractor.phpsrc/jwt/src/Contracts/ValidationContract.phpsrc/jwt/src/Exceptions/SecretMissingException.phpsrc/jwt/src/Http/Middleware/AuthenticateAndRenew.phpsrc/jwt/src/Http/Middleware/RefreshToken.phpsrc/jwt/src/Http/Parser/AuthHeaders.phpsrc/jwt/src/Http/Parser/Cookie.phpsrc/jwt/src/Http/Parser/InputSource.phpsrc/jwt/src/Http/Parser/Parser.phpsrc/jwt/src/JWTManager.phpsrc/jwt/src/JWTServiceProvider.phpsrc/jwt/src/JwtGuard.phpsrc/jwt/src/Providers/Lcobucci.phpsrc/jwt/src/Validations/ExpiredClaim.phpsrc/jwt/src/Validations/IssuedAtClaim.phpsrc/jwt/src/Validations/IssuerClaim.phpsrc/jwt/src/Validations/NotBeforeClaim.phpsrc/support/src/Facades/JWT.phpsrc/testbench/hypervel/.env.exampletests/AfterEachTestSubscriber.phptests/JWT/ClaimFactoryTest.phptests/JWT/Console/JwtGenerateCertsCommandTest.phptests/JWT/Console/JwtSecretCommandTest.phptests/JWT/Http/Middleware/AuthenticateAndRenewTest.phptests/JWT/Http/Middleware/RefreshTokenTest.phptests/JWT/Http/ParserTest.phptests/JWT/JWTConfigTest.phptests/JWT/JWTManagerTest.phptests/JWT/JWTServiceProviderTest.phptests/JWT/JwtGuardCoroutineSafetyTest.phptests/JWT/JwtGuardEventTest.phptests/JWT/JwtGuardSubjectLockTest.phptests/JWT/JwtGuardTest.phptests/JWT/Providers/LcobucciTest.phptests/JWT/Validations/IssuerClaimTest.phptests/JWT/Validations/NotBeforeClaimTest.php
Harden JWT certificate generation by validating supported SHA variants, enforcing EC curve/SHA compatibility, checking key writes, and securing generated private keys before writing environment values. Protect package-managed JWT claims from user-provided custom claims, keep refresh from invalidating the old token until the replacement has been signed, and ensure refresh still enforces future not-before claims. Tighten token parsing by defaulting the parser chain to authorization headers only and parsing comma-separated Authorization segments by scheme instead of matching stray Bearer substrings. Clear default guard user context during JWT logout/forgetUser flows so default cached users cannot resurface after token override cleanup. Document worker-lifetime guard mutators across JWT and session guards, add the shared provider mutator warning, and replace nearby container array access with explicit make() calls. Adds regression coverage for certificate variants and failures, reserved claim rejection, refresh invalidation ordering, not-before refresh validation, parser behavior, config defaults, and guard context cleanup.
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tests/JWT/JWTConfigTest.php (1)
152-158: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winFlush
Envbefore asserting parser defaults.This test is reading an env-backed config file, but unlike the surrounding config tests it skips
Env::flushRepository(). That makes the default-parser assertion order-dependent if another test has already populated the env repository.Suggested fix
public function testDefaultParserOnlyIncludesAuthorizationHeaders(): void { + Env::flushRepository(); + $config = require dirname(__DIR__, 2) . '/src/jwt/config/jwt.php'; $this->assertSame([AuthHeaders::class], $config['parser']); $this->assertNotContains(InputSource::class, $config['parser']); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/JWT/JWTConfigTest.php` around lines 152 - 158, The default parser config test is missing the same env cleanup used by the other config tests, so its assertions can become order-dependent. Update testDefaultParserOnlyIncludesAuthorizationHeaders in JWTConfigTest to flush the env repository with Env::flushRepository() before loading src/jwt/config/jwt.php, matching the surrounding config test setup and keeping the parser defaults assertion isolated.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@tests/JWT/JWTConfigTest.php`:
- Around line 152-158: The default parser config test is missing the same env
cleanup used by the other config tests, so its assertions can become
order-dependent. Update testDefaultParserOnlyIncludesAuthorizationHeaders in
JWTConfigTest to flush the env repository with Env::flushRepository() before
loading src/jwt/config/jwt.php, matching the surrounding config test setup and
keeping the parser defaults assertion isolated.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: d760cc51-06ae-493b-822f-e46a9a436a65
📒 Files selected for processing (19)
src/auth/src/AuthManager.phpsrc/auth/src/AuthServiceProvider.phpsrc/auth/src/GuardHelpers.phpsrc/auth/src/SessionGuard.phpsrc/boost/docs/jwt.mdsrc/jwt/config/jwt.phpsrc/jwt/src/ClaimFactory.phpsrc/jwt/src/Console/JwtGenerateCertsCommand.phpsrc/jwt/src/Http/Parser/AuthHeaders.phpsrc/jwt/src/JWTManager.phpsrc/jwt/src/JWTServiceProvider.phpsrc/jwt/src/JwtGuard.phpsrc/jwt/src/Validations/NotBeforeClaim.phptests/JWT/ClaimFactoryTest.phptests/JWT/Console/JwtGenerateCertsCommandTest.phptests/JWT/Http/ParserTest.phptests/JWT/JWTConfigTest.phptests/JWT/JWTManagerTest.phptests/JWT/JwtGuardTest.php
💤 Files with no reviewable changes (1)
- src/jwt/config/jwt.php
✅ Files skipped from review due to trivial changes (2)
- src/auth/src/GuardHelpers.php
- src/auth/src/SessionGuard.php
🚧 Files skipped from review as they are similar to previous changes (9)
- src/boost/docs/jwt.md
- tests/JWT/Http/ParserTest.php
- src/jwt/src/JWTManager.php
- src/jwt/src/Console/JwtGenerateCertsCommand.php
- src/jwt/src/JWTServiceProvider.php
- tests/JWT/ClaimFactoryTest.php
- tests/JWT/JWTManagerTest.php
- tests/JWT/JwtGuardTest.php
- src/jwt/src/JwtGuard.php
Remove the JWT sliding refresh middleware aliases and document the explicit refresh endpoint pattern instead. Refreshing tokens on ordinary request middleware turns normal traffic into token rotation traffic, adds blacklist writes, and creates avoidable concurrent-request races. Make blacklist storage resolution lazy so applications with blacklist disabled do not resolve cache-backed blacklist storage. Add a fail-fast taggable-store check only for the default TaggedCache storage while allowing custom storage implementations to define their own requirements. Update the Lcobucci provider to use the current immutable withValidationConstraints API and round blacklist TTLs up so fractional minute differences cannot expire blacklist entries early. Add regression coverage for disabled blacklist lazy resolution, tagged-cache capability checks, custom storage bypass behavior, alias removal, and blacklist TTL rounding. Update the JWT docs and plan addendum to capture the final Tymon follow-up decisions.
|
Added a follow-up commit for the Tymon JWT review findings: Summary of the changes:
Reasoning:
Validation:
|
Summary
Refactors the JWT package into a complete Hypervel-native authentication implementation while keeping the existing array payload model and adapting the internals for long-lived Swoole workers. This brings in the missing features from tymondesigns/jwt-auth / php-open-source-saver/jwt-auth, and fixes some security holes.
The package now includes centralized claim construction, optional
JWTSubjectsupport, issuer / issued-at / not-before validation, subject locking,hasListeners()guarded auth events, coroutine-scoped guard state, token parser/extractor support, secret and certificate generation commands, expanded configuration, and full documentation.See plan for more details: docs/plans/2026-06-28-0709-jwt-hypervel-native-parity-refactor.md
Details
ClaimFactoryfor standard claims, custom model claims, provider subject locking, issuer stamping, and refresh claim handling.JWTSubjectsupport without requiring normalAuthenticatablemodels to implement a JWT-specific contract.JwtGuardso token, payload, user, TTL, custom-claim, and last-attempted state are isolated through coroutine context.attempt,once,onceUsingId, refresh, invalidation, and one-shot custom-claim behavior.hasListeners-guarded auth events so event objects are only built and dispatched when listeners exist.jwt:secretandjwt:generate-certscommands, including HMAC, RSA, EC, passphrase, overwrite, and missing-env-file behavior.NotBeforeCliamclass toNotBeforeClaimand verifies stale references are gone..env.example; only the Testbench app skeleton receives application-style JWT env examples.Coroutine Safety And Performance
hasListenersguard pattern.Testing
composer fixgit diff --checkgit -C ../hypervel diff --checkSummary by CodeRabbit
New Features
Bug Fixes
Documentation