tourze/access-key-bundle
A Symfony bundle from the Tourze collection for managing access keys. It offers services and configuration to generate, store, and validate keys, helping secure APIs and internal endpoints with framework-native integration.
Before you run composer require, note the shape of this package: tourze/access-key-bundle is a Symfony bundle, not a Laravel package. There is no Illuminate\Support\ServiceProvider, no config file published via vendor:publish, and no facade. Day-to-day "leverage" for a Laravel developer therefore splits into two paths: (a) you're running this inside a Symfony service that talks to your Laravel app, or (b) you're reading it as prior art for rolling your own API-key middleware. Decide which you're doing first — it changes everything else.
Where to look first
composer.json — check "type": "symfony-bundle", the PHP floor, and the symfony/* constraints. A 1.x→2.0 jump almost always means a PHP 8.2+/Symfony 7 floor bump.src/ — the access-key model/entity and whatever service validates a presented key. This is the actual product.DependencyInjection/ — the Configuration class tells you every tunable option and its default. In a Symfony bundle this is the documentation.README / the 1.0.1...2.0.0 compare link — the release note here is only a changelog URL, so the diff is your only record of what broke.First use case
Protecting an internal HTTP API with per-client keys stored in your own database, rather than hand-rolled bearer tokens. Install in a Symfony host:
composer require tourze/access-key-bundle
then register the bundle in config/bundles.php, add any required config under config/packages/, and run bin/console config:dump-reference <bundle_alias> to see the real option tree before guessing at YAML keys. If you were hoping to drop this into a Laravel app/Http/Middleware, stop now — port the idea, not the code.
Database-backed keys with a lookup prefix. The pattern these bundles implement is: store a non-secret keyId/prefix in plaintext for indexing, store a hash of the secret, and compare in constant time. That means your schema work is a normal Doctrine migration, and your Laravel-side equivalent is a access_keys table with (key_id, hashed_secret, owner_id, expires_at, last_used_at).
Header extraction is the integration seam. In Symfony the bundle reads the request (typically an X-Access-Key style header) inside an event subscriber or authenticator. Map that 1:1 onto Laravel middleware:
// App\Http\Middleware\AuthenticateAccessKey
$key = $request->header('X-Access-Key');
$record = AccessKey::where('key_id', substr($key, 0, 12))->first();
abort_unless($record && hash_equals($record->hashed_secret, hash('sha256', $key)), 401);
Keep the auth concern out of controllers. The bundle's value is that verification happens before your handler runs; replicate that by resolving the key owner into the container ($request->attributes->set('accessKeyOwner', ...) in Symfony, Auth::setUser() or a request attribute in Laravel) so downstream code never re-parses the header.
Rotation and expiry as first-class fields. Add expires_at, revoked_at, and last_used_at. A key bundle that only does presence-checks will bite you the first time a partner leaks a token. last_used_at also gives you free dead-key cleanup.
Testing. Create a known key in a fixture/seed and assert both the 200 path and the 401 path; assert that a revoked key fails, because that's the branch that silently regresses during refactors.
^1.0 until you've read the diff, and check composer.json for a PHP/Symfony floor bump before upgrading in a shared lockfile.bundles.php, nothing errors loudly — the service just never wires up and your middleware silently never runs. Verify with bin/console debug:container | grep -i access.EntityManagerInterface. If your host app uses Eloquent, you're maintaining a mapping layer; budget for it or don't adopt.hash_equals, not ===. Comparison-based auth is the classic timing-leak footgun, and it's easy to reintroduce when you "simplify" the check later.laravel/sanctum with abilities covers most of this, and a hand-written middleware (~40 lines, shown above) covers the rest. Reach for the bundle only if the Symfony host is already committed to it.How can I help you explore Laravel packages today?