overtrue/laravel-passport-cache-client
Caches Laravel Passport access tokens, clients, and scopes in Redis or any cache store, eliminating repeated database queries during authentication. Drop-in service provider with configurable TTL and cache driver, working alongside existing Passport setups.
overtrue/laravel-passport-cache-client is a small decorator around Laravel Passport's ClientRepository that caches oauth_clients lookups, so token issuance (POST /oauth/token), personal access token creation, and Client::find() calls stop hitting the oauth_clients table on every request.
2.1.1 is a patch release — the only artifact published is a compare link against 2.1.0 with no feature, fix, or breaking-change notes. Treat it as a drop-in replacement: bump the constraint, run the suite, ship. Nothing in the release warrants new configuration or migration work.
Minimal steps:
php artisan passport:install, keys generated, oauth_clients populated). This package replaces a binding Passport owns — installing it before Passport is configured just gives you an empty cache of nothing.composer require overtrue/laravel-passport-cache-client — the service provider is auto-discovered, there is no manual config/app.php entry.php artisan vendor:publish --provider="Overtrue\LaravelPassportCacheClient\PassportCacheClientServiceProvider"// php artisan tinker
get_class(app(Laravel\Passport\ClientRepository::class));
// should NOT be Laravel\Passport\ClientRepository
First use case: a token endpoint under load. Open Telescope (or DB::listen) on a staging box, hit /oauth/token twice, and watch for the select * from oauth_clients where id = ? query disappearing on the second call. That single query is the entire value proposition; if it's still there, the binding was overridden or the cache is misconfigured and you should stop before tuning TTLs.
Where to look first: the published config file (store, TTL, key prefix), then PassportCacheClientServiceProvider to see exactly which bindings it touches in your installed version — the README tracks 2.x loosely and the provider is the source of truth.
Zero-config drop-in for the common case. Most apps should install it, point it at a shared cache store (Redis/Memcached, not file or array), set a TTL you can defend, and change nothing else. Passport's own code paths — password grant, client credentials, personal access tokens, passport:client — all go through the repository, so they all benefit without edits.
Production config shape. The two knobs that matter:
file cache on three load-balanced servers means three divergent views of your clients; a secret rotated on one node is still live on the others until TTL expiry.Deploy-hook invalidation. The single most useful integration pattern: whenever a deploy includes anything that writes to oauth_clients — a seeder, a migration that alters client flags, a credential rotation script — clear the client cache as part of the release. Wire it into your deploy script next to config:cache and queue:restart. This lets you keep a longer TTL without a correctness risk.
Write through Eloquent, not SQL. Updates that go through the client model let the package's model events invalidate the relevant entry. Raw DB::table('oauth_clients')->update(...) in an admin panel, seeder, or another service bypasses that entirely and leaves a stale entry sitting there. If you have a custom client-management UI, either use the model or explicitly forget the entry after writing.
Multiple clients / multi-tenant. Each client is cached under its own key, so many clients is fine — but the cache prefix must be environment-scoped. Staging and production sharing a Redis instance with the same prefix will happily serve each other's client records, and the failure mode (wrong redirect URI, wrong grant type) is confusing rather than loud.
Test suite isolation. Tests that create a client via factory, hit the token endpoint, then delete/refresh the DB will inherit cached entries keyed to recycled IDs on SQLite. Either set the package's cache store to array in phpunit.xml / phpunit.xml.dist (fast, no cross-test leakage) or flush the client cache in setUp. Don't let CI silently test against a warm cache from a previous test.
Long-lived workers (Octane, Horizon, queue). Because caching lives in Laravel's cache rather than process memory, workers mostly behave. The exception is the array store, which under Octane persists per-worker across requests — safe for tests, wrong for a daemon.
Extend rather than fork. If you need custom key naming, tagging, or a warm-up command, subclass the package's cache repository and rebind Laravel\Passport\ClientRepository in your own provider registered after Passport's. Keep the override in one place; scattering rebinds across providers is how you end up debugging which repository won.
personal_access_client / password_client flags are cached too. The repository caches the flag-based lookups, not just find($id). Flipping a client from password grant to client-credentials in the DB without clearing the cache means Passport keeps validating against the old shape. Symptom: unsupported_grant_type or invalid_client for a client you "already fixed."cache:clear runs. Conversely, a stale cache is worse than no cache; when in doubt, flush.ClientRepository binding (common with custom client models or a tenancy setup), check which one wins: app(ClientRepository::class) in tinker is the only reliable answer. Silent last-write-wins is the usual cause of "the package isn't doing anything."Passport::useClientModel() interacts with this. A custom client model plus a cached repository is fine, but confirm the cached records are hydrated as your model — otherwise you get base Client instances without your accessors/scopes and subtle null-related bugs downstream.get_class(app(ClientRepository::class)); (2) config's store/TTL actually loaded (config('...') — remember config:cache in production freezes it); (3) DB::listen or Telescope on two consecutive token requests; (4) inspect the cache keys directly in Redis (SCAN on your prefix). Ninety percent of "it isn't caching" reports are a config cache that predates the install./oauth/token, this package's win shrinks and its invalidation surface grows. Measure the query first.^2.1 and read the diff between tags before bumping minor versions — the changelog alone won't tell you whether a binding or config key moved.How can I help you explore Laravel packages today?