jwt and basic — and both are sessionless. Neither writes a session cookie, reads a remember token, or maintains server-side auth state between requests. On every request the guard reads the credentials from the incoming HTTP request, resolves the identity and principal from your configured provider and resolver, and binds the contextual triple before your application code runs. When the request ends, that state is discarded.
The JWT guard (driver: jwt)
The JWT guard reads the Authorization: Bearer <token> header. When a token is present it decodes the JWT, validates the standard claims (iss, aud, typ, exp, and a configurable leeway), and then rehydrates the full contextual triple from live database state:
- The
subclaim is used to load the identity from the configured provider. - If the identity implements
CanBeActive, the guard callsisActive()and rejects the request onfalse. - The
pidclaim, if present, is passed to the principal resolver as a hint. The resolver must return a principal whosegetPrincipalIdentifier()matches the hint exactly — the guard fails closed if the hint resolves to a different principal. - The
didclaim, if present and if the identity implementsHasDevices, is used to load the device record. Adidthat does not resolve to a known device causes the request to be rejected rather than silently downgraded to “no device.” - All three objects are bound to the guard, making them available via
Auth::identity(),Auth::principal(), andAuth::device().
Access tokens are self-contained and validated without a server-side token store. Revoking a device blocks refresh for that device, but already-issued access tokens remain valid until expiry unless the identity, principal, or device can no longer be rehydrated from live state.
$guard->refresh($refreshToken) to exchange a refresh credential for a new access token and a rotated refresh token. The exchange validates the refresh token’s JWT claims, verifies the stored rotation digest with hash_equals, atomically rotates the device’s refresh key, and re-binds the contextual triple — all in one round trip.
The HTTP Basic guard (driver: basic)
The HTTP Basic guard reads PHP_AUTH_USER and PHP_AUTH_PW from the active request (surfaced as $request->getUser() and $request->getPassword()). When both are present it runs them through a timing-safe credential validation path:
- The username is looked up in the configured provider using the guard’s
identifier_field(defaults toemail). - The entire retrieve-and-validate pipeline runs inside a
Timeboxwith a configurable duration (default 400 ms). The elapsed time is uniform whether or not the identifier resolves, preventing user-enumeration via timing side-channel. - On valid credentials, the guard checks the identity’s active state and resolves a principal via the
PrincipalResolver. - The identity and principal are bound to the guard. Because Basic auth carries no device token,
Auth::device()always returnsnullfor this guard.
Registering guards in config/auth.php
Register either guard exactly as you would any first-party Laravel guard — no service provider call required:
Identity (and optionally Principal, HasPrincipals, HasDevices, CanBeActive). The guard infers which capabilities are available at runtime from the interfaces on the resolved model — no configuration flag needed.
Using guard middleware
Apply guards with standard Laravel middleware exactly as documented in the framework:How the contextual triple is exposed
Both guards store the resolved identity, principal, and device on the guard’s state after a successful authentication. TheAuth facade forwards contextual accessor calls to the currently active guard:
user() call that Laravel triggers on the first Auth::check() or route middleware pass.
Multiple guards with separate trust boundaries
You can register multiple JWT guards, each with its own signing secret, audience claim, and principal resolver. Tokens issued under one guard cannot authenticate against another because theaud claim is enforced on every parse:
auth:staff or auth:customer middleware. Tokens minted for the staff-api audience are rejected by the customer guard, and vice versa. Each guard can also carry its own kid-rotation set for fully independent signing-key lifecycles.
Issue tokens through the guard-scoped JWT service so the audience and signing material match the guard that will later verify them:
JWT configuration
Configure signing secrets, key rotation, TTLs, leeway, and per-guard JWT overrides.
Advanced configuration
Per-guard principal resolvers, identifier fields, resolution caching, and timebox tuning.