ma27/api-key-authentication-bundle
Symfony bundle that adds API key authentication to your app. Validate keys from request headers or query parameters, resolve them to users via a provider, and protect firewall routes for REST APIs and machine-to-machine access with minimal configuration.
Verdict up front — revised, conclusion unchanged. The 2.0.0-alpha1 release changes the package's maintenance story but not its applicability. It remains a Symfony bundle with no Laravel service provider, guard driver, facade, or middleware, and no third-party bridge. What has changed is that the "archived since 2016" framing is now stale: there is an active maintainer and a modernization branch. That is a genuine positive signal for the project, but it is delivered as an explicitly non-production-ready alpha whose own release notes warn that "some parts of the docs might be out-of-date." The recommendation stands: port the design, do not install the package. The 7.16 "opportunity" score still measures the problem space (API-key auth is a recurring need), not this artifact's viability.
Architecture fit. Unchanged and structurally disqualifying for Laravel. The bundle registers via Symfony's Bundle class and DI extension, wires an authentication provider into the Symfony security firewall, and is configured through a ma27_api_key_authentication root in Symfony's config tree. Laravel exposes none of those primitives — no bundles, no firewall factories, no AuthenticationProviderInterface. The release notes describe "improvements regarding the internal design," which, if they mean migration onto the post-5.3 / 6.0+ Symfony security contracts, would make the package more Symfony-idiomatic and therefore no closer to Laravel. This is unverified — the notes contain no technical detail and the changelog contents were not supplied.
Integration feasibility. Still port, do not install, at the same cost profile. The reusable surface remains small: a key entity/model, a generator, a verification routine, and a request-side auth hook. The alpha status does not reduce porting effort; it slightly increases it, because the reference implementation is now a moving target with no backwards-compatibility promise between pre-releases. Pin the exact tag (2.0.0-alpha1) or commit SHA used for the read, and record it in the spike memo so the port is traceable to a known source. The Laravel-native build is unchanged: migration + Eloquent model for keys, Str::random/random_bytes for generation, hash('sha256', …) with hash_equals() for constant-time verification, a custom guard registered via Auth::extend, and an auth.apikey middleware.
Technical risk. Still high and concentrated on the authentication path, with one risk retired and two added.
Retired (partially): abandonment. There is an active maintainer and a release cadence again. Do not over-read this — one alpha after a multi-year gap is an intent signal, not a support commitment.
Added:
Unchanged and still to be validated in the spike:
composer.json — still the fastest way to end the investigation.random_bytes/openssl_random_pseudo_bytes or better only.hash_equals only.last_used_at are still expected to be net-new work regardless of the package.Key questions for the spike — updated.
2.0.0 changelog actually list? Specifically: minimum PHP, supported Symfony versions, and whether it targets the 6.x security contracts. (Blocking — this determines whether the reference code is even instructive.)1.x and 2.0.0-alpha1, and how much is Symfony plumbing versus key logic?Stack fit. Unchanged: PHP 8.x-era Symfony bundle against Laravel 10/11. The language is shared; essentially nothing else is. Cross-framework read-and-port, not an integration. The 2.0 line, if anything, deepens the Symfony coupling by modernizing against newer Symfony contracts.
Migration path. Do not add this to composer.json. An alpha-status package on the authentication path is a worse supply-chain decision than the archived version was, because an alpha implies imminent breaking change rather than stable stagnation. Instead:
2.0.0-alpha1 — or simply copy the ~5 relevant classes into a scratch branch as a reference. Retain attribution in a NOTICE or file header if any code is carried over verbatim, and note the source tag.api_keys table (id, keyable morph, name, prefix, hash unique-indexed, scopes json, expires_at, last_used_at, revoked_at, timestamps); ApiKey model; ApiKeyGuard implementing Illuminate\Contracts\Auth\Guard; AuthenticateApiKey middleware aliased in bootstrap/app.php; a php artisan api-key:issue command for ops.Hash/hash_equals, Str::random(48), config publishing, and the existing rate limiter (RateLimiter::for('api')) keyed on the API key rather than IP.Compatibility. Assume incompatibility until proven. The 2.0 branch may well widen the supported-Symfony range while remaining entirely outside Laravel's orbit; treat "supports Symfony 6" as irrelevant to our decision. The only compatibility posture that survives the next Laravel major is a rewrite of the internals with zero shared runtime dependencies.
Sequencing — one step amended.
pk_live_… for identification + secret hash), hashing scheme, scope model, expiry/rotation policy, revocation semantics. Sign off with security.Maintenance. Ownership still transfers to us on day one, because we will not be installing the package. The maintenance outlook for the upstream project has improved from "dead" to "pre-release revival," which matters for the reference implementation only: it means the source we read will likely still exist and get fixes, so the code we port is less likely to be a snapshot of an abandoned approach. It does not change our upkeep budget — ~2–4 engineer-days per year for our own module, driven mostly by Laravel major upgrades.
Support. Revised upward, cautiously. There is now a maintainer and a release channel; the previous "no upstream maintainer, no community" assessment is no longer accurate as written. But 8 stars and 0 dependents still mean no third-party corpus, no Stack Overflow history, and no ecosystem of write-ups — 2.0 being an alpha means the small corpus that does exist may describe the old architecture and be actively misleading. Treat upstream as a courtesy channel, not a support contract. Our API-key module needs a named owner in the on-call runbook.
Scaling. Unchanged and independent of the release, since we are not running their code. Verification is on every authenticated request, so the hot path must be O(1): a unique index on the key hash, lookup by hash rather than iterating candidates, and a Redis cache for key→principal resolution with explicit invalidation on revoke. Plan a short TTL (30–60s) with revoke-on-write invalidation and accept the bounded revocation window as a documented, reviewed tradeoff. last_used_at writes must be sampled or queued, never per request, or the read path becomes a write path under load. Note: if the 2.0.0 "performance improvements" are meaningful, they accrue to Symfony users; they do not transfer to a native Laravel implementation.
Failure modes to design against.
hash_equals only; lint rule or review checklist.throttle incorrectly, yielding unthrottled authenticated traffic. Explicit route-group ordering and a test.expires_at → premature or late expiry across nodes. UTC everywhere, small grace window.Ramp-up. Shallow for anyone who knows Laravel — the ported surface is tiny and uses framework-native primitives. The real cost is un-learning the Symfony idioms, which is why reading the bundle is a spike activity, not a training investment. 1 engineer-day to reach confident comprehension of the original, 2–3 days for a mid-level engineer to own the first-party replacement. The organizational risk is unchanged and arguably sharpened: a fresh 2.0.0 release creates a stronger false signal that API-key auth is "solved and maintained," when the package still supplies only a fraction of a production key system (rotation, scopes, expiry, audit, revocation) and supplies it in the wrong framework. The alpha tag mitigates this only for readers who get past the headline.
How can I help you explore Laravel packages today?