Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Api Key Authentication Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Read the status line first — it just changed. The bundle is no longer a dead 2016 artifact: 2.0.0-alpha1 has been published on a new 2.0.0 branch, with the release notes citing "improvements regarding the internal design and performance." That said, the notes are almost content-free: it is an alpha, explicitly "not production-ready," and the maintainers warn that "some parts of the docs might be out-of-date." So the correct posture is still "how do I use this if I inherit a project that depends on it" — but the question is now which line you inherited, 0.2.x or 2.0.x, because those are almost certainly different codebases.

Decide which branch you're on before anything else.

  • 0.2.x — the archived-era line. Symfony 2.8/3.x, PHP 5.6–7.0, AppKernel registration, YAML under app/config/. All of the old caveats apply.
  • 2.0.x — alpha. A major-version bump from 0.2 means breaking changes by definition; the changelog (CHANGELOG.md#200) is the only authoritative source for what moved, and you should read it before writing a single line. Expect service IDs, namespaces, and possibly bundle registration (Flex vs. AppKernel) to differ.

1. Install — pin, and be explicit about stability. Pre-releases don't resolve under default stable minimum-stability:

# New line (alpha — pin the exact tag, never a range)
composer require "ma27/api-key-authentication-bundle:2.0.0-alpha1"

# Legacy line
composer require "ma27/api-key-authentication-bundle:^0.2"

If Composer explodes on symfony/* constraints, that's the signal to stop rather than force it with --ignore-platform-reqs. Run composer why-not symfony/framework-bundle early — on the alpha especially, this tells you whether "internal design improvements" actually bought you modern Symfony/PHP support or not. The release notes do not state the supported PHP or Symfony versions; verify from composer.json in vendor/, not from the announcement.

2. Register the bundle. On 0.2.x, app/AppKernel.php:

$bundles = [
    // ...
    new Ma27\ApiKeyAuthenticationBundle\Ma27ApiKeyAuthenticationBundle(),
];

On 2.0.x under Symfony Flex this is normally automatic via the recipe; if the bundle isn't in config/bundles.php, add it there. Don't assume — check.

3. Wire the firewall — still the piece that determines whether anything works, and the most likely thing to have been renamed in a major:

# 0.2.x: app/config/security.yml — 2.0.x: config/packages/security.yaml
security:
    providers:
        api_key_provider:
            id: ma27_api_key_authentication.user_provider   # verify on 2.0 via debug:container

    firewalls:
        api:
            pattern: ^/api
            stateless: true
            provider: api_key_provider
            simple_preauth:
                authenticator: ma27_api_key_authentication.authenticator

If 2.0 moved to Symfony's AuthenticatorInterface/security.authenticator model, simple_preauth may be gone entirely — the release notes don't say, so treat the block above as the 0.2 shape and confirm against the alpha's own docs/tests.

4. Annotate the User entity — unchanged in intent; the bundle reads which properties hold credentials and the key via annotations, so your column names stay yours:

use Ma27\ApiKeyAuthenticationBundle\Annotation as ApiKeyAuth;

class User implements ApiKeyUserInterface
{
    /** @ApiKeyAuth\ApiKeyCredential */
    private $username;

    private $password;

    /** @ApiKeyAuth\ApiKey */
    private $apiKey;
}

5. Configure the bundle (app/config/config.yml on 0.2, config/packages/ma27_api_key_authentication.yaml on Flex):

ma27_api_key_authentication:
    user_class: AppBundle\Entity\User
    login_route: api_login
    api_key_header: X-Api-Key
    api_key_param: apiKey           # query-string fallback

First use case to get working end-to-end: POST /api/login with username/password returning a key, then GET /api/foo with X-Api-Key: <key> returning data instead of a 401. Get that loop green before touching anything else — every other feature is downstream of it, and on the alpha it is also your fastest smoke test that the "internal design improvements" didn't break the public contract.

Where to look first:

  • bin/console debug:container | grep ma27 — on 2.0.x the service IDs are the first thing to re-verify; internal redesign is exactly what renames services.
  • bin/console debug:router — confirm login_route points at a route the bundle actually handles.
  • vendor/ma27/api-key-authentication-bundle/Model/ — the manager interfaces are the extension points you'll actually implement.
  • The alpha's own test suite and CHANGELOG.md#200 — with stale docs, these are the spec.

Implementation Patterns

Firewall isolation. Put the API firewall before your main firewall and give it a narrow pattern (^/api). A stateless: true firewall that accidentally matches browser routes will log users out of the web UI by overwriting the security context.

Header-first, query-param-never. The bundle supports both api_key_header and api_key_param because 2016-era clients sometimes couldn't set headers. The query param remains a liability: keys leak into access logs, browser history, and Referer headers. Keep it configured if you must, never document it, and filter apiKey out of your request logger.

Custom storage for keys. The bundle ships Doctrine ORM/ODM managers, but the clean integration point is implementing the key-manager interface and registering your own service. That lets you store keys hashed (bcrypt/argon2) rather than plaintext — the bundle's own entities stored keys as-is, which is the single biggest thing to fix if you're keeping it:

class HashedKeyManager implements ApiKeyManagerInterface
{
    public function getKeyForUser(ApiKeyUserInterface $user): string
    {
        // random_bytes(32), hex-encode, persist hash, return plaintext once
    }
}

On 2.0.x, re-check the interface signature before implementing — a major bump that touches "internal design" is very likely to have changed this contract, and the compiler will tell you faster than the docs will.

Issue and revoke keys outside the login flow. A small admin controller or console command that calls the key manager directly is how you support "regenerate my key" and "revoke this key" without making users log in with a password they may not have. The bundle gives you the model layer; it does not give you the endpoints.

Controllers stay boring. Because authentication happens in the firewall, your REST controllers never touch keys:

public function listAction()
{
    $user = $this->getUser();   // populated by the pre-auth listener
    // ...
}

If you find yourself injecting an "authentication service" into controllers, the firewall wiring is wrong.

Integration testing pattern. Functional tests are where this bundle earns its keep — you can assert the whole loop:

$client->request('POST', '/api/login', ['username' => 'u', 'password' => 'p']);
$key = json_decode($client->getResponse()->getContent(), true)['key'];

$client->request('GET', '/api/foo', [], [], ['HTTP_X_API_KEY' => $key]);
$this->assertSame(200, $client->getResponse()->getStatusCode());

Upgrade 0.2 → 2.0 as a spike, not a branch. Because the alpha's docs are stale, the only honest way to scope the move is a throwaway branch: bump the constraint, composer update ma27/*, run your existing functional auth tests, and count the failures. If the loop above is green and your managers still type-check, the migration cost is small; if simple_preauth or the manager interfaces vanished, treat it as a re-integration rather than an upgrade.

Migration path (unchanged, still the best one). If you're modernizing, the cheapest route is to keep the bundle's key storage — existing users' keys keep working — and replace only the authenticator with a Symfony-native one that reads X-Api-Key, looks up the hash, and returns a SelfValidatingPassport. That's a contained change you can ship in one PR, and it insulates you from whatever 2.0.x does next.

Gotchas and Tips

"Un-archived" is not "stable." This is the biggest update to the old assessment: the project is being worked on again, but 2.0.0-alpha1 is a pre-release that the maintainers say is not production-ready. Do not take the version bump as license to lift the ban on greenfield use. It means the abandonment risk is now uncertain rather than certain — a live alpha can still be abandoned, and an alpha API can still churn before GA.

No changelog in the release notes means no trust in the release notes. "Internal design and performance" tells you nothing about whether simple_preauth, the annotation reader, or the manager interfaces survive. Before planning any work against 2.0.x, read CHANGELOG.md#200 and diff the bundle's composer.json against your project's — supported PHP and Symfony ranges are the go/no-go fact that the announcement omits entirely.

Pin the alpha to the exact version, and commit the lockfile. A branch alias or a ^2.0@alpha range will silently pull alpha2, alpha3, beta1 with changed service IDs and no migration notes. Exact tag plus a committed composer.lock is the only way to keep the alpha from moving under you.

Annotations require a reader. If sensio/framework-extra-bundle isn't installed or the annotation reader isn't registered, @ApiKeyCredential silently does nothing and every authentication attempt fails with an unhelpful "user not found." Symptom: correct credentials, consistent 401, no exception. On newer Symfony this is a real risk — also watch for PHP 8 attribute-only support replacing annotations. Check the reader before debugging anything else.

Cache clear after config changes. ma27_api_key_authentication config is compiled into the container. Changing user_class or login_route without bin/console cache:clear gives stale behavior that looks like a code bug.

Provider ID must be the bundle's provider. Configuring a Doctrine entity: provider instead of the bundle's id: provider is a common copy-paste error — it "works" for loading users but the key lookup path never runs, so valid keys are rejected. Verify with debug:container, and re-verify on 2.0.x where the ID may have changed.

Default hashing is weak. The bundle's key generation/hashing defaults are period-appropriate but not modern. If hash_algorithm is configurable, it's not a substitute for storing hashes rather than plaintext keys. Migrate keys by reissuing on next login.

Firewall ordering and anonymous. anonymous: ~ on an API firewall defeats the point — the pre-auth listener may never run because the request already has an anonymous token. Omit it entirely on the API firewall.

Key collisions and regeneration. If you implement key generation yourself, use random_bytes() and enforce a unique index; sequential or time-based keys are guessable. Decide what happens on regeneration: old key invalid immediately (safer) vs. grace period (friendlier), and document it.

Debugging toolkit. security.access_control denials, not authentication failures, are the usual cause of "my key stopped working" — check the profiler's Security panel before touching the bundle. Set a ma27 monolog channel if the bundle logs there; otherwise add temporary dump()s in the listener. On the alpha, add a first test that just asserts the container has the authenticator service — it turns a class of wiring regressions into an instant failure.

Extension points worth knowing: the user manager, the key manager, and the authenticator service. Override the managers via service decoration or a parameters.yml class swap; the authenticator is the hardest to replace in-place — prefer replacing it wholesale during migration. Note that 2.0's "internal design" work may have already reshaped these seams, so confirm against vendor/ before building on them.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core