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 Guard Laravel Package

chrisbjr/api-guard

API Guard is a Laravel package for API key authentication. It lets you generate and manage API keys, protect routes with middleware, and authenticate requests via configurable headers or query parameters, with hashed key storage and easy integration.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install (and mind the version). chrisbjr/api-guard was last released in 2016, so it targets Laravel 5.x. If you're on a modern Laravel, expect either a fork or a --ignore-platform-reqs install plus manual fixes; on Laravel ≤5.4 you'll also need to register the service provider in config/app.php.

composer require chrisbjr/api-guard
php artisan vendor:publish --provider="Chrisbjr\ApiGuard\Providers\ApiGuardServiceProvider"
php artisan migrate

2. Register the middleware alias in app/Http/Kernel.php (check the package README for the exact class name in your version):

protected $routeMiddleware = [
    // ...
    'auth.apikey' => \Chrisbjr\ApiGuard\Http\Middleware\AuthenticateApiKey::class,
];

3. Look at the two files that matter. config/apiguard.php (header name, query-string fallback, model binding, ignored routes) and the published migration for api_keys. Everything else in the package is a thin middleware around those two.

4. First use case — protect a route group and issue a key.

Route::group(['prefix' => 'api/v1', 'middleware' => 'auth.apikey'], function () {
    Route::get('/orders', 'Api\OrderController@index');
});
use Chrisbjr\ApiGuard\Models\ApiKey;

$apiKey = ApiKey::generate($user->id);   // persists the row
return response()->json(['key' => $apiKey->key]);
curl -H "X-Api-Key: <key>" https://app.test/api/v1/orders

If the key is bound to a user, the middleware logs that user in, so auth()->user() / $request->user() work normally inside your controller.

Implementation Patterns

Issue keys as part of registration, not by hand. Generate on signup (or on "create API credential" in a settings page) and return the plaintext key exactly once:

$apiKey = ApiKey::generate($user->id);
return response()->json(['api_key' => $apiKey->key], 201);

Because the model is polymorphic (user_id + user_type), the same pattern works for teams, tenants, or service accounts.

Multiple keys per consumer. One key per device or per environment (staging/prod) makes revocation surgical. Store a human label alongside the key.

Revocation is a row delete. There's no caching or token introspection indirection, so $apiKey->delete() is effective on the next request. This is the package's biggest operational strength — no blacklist logic to maintain.

Use the query-string fallback only for clients that can't set headers. The config exposes a query_key (default api_key) for webhooks and legacy integrations. Prefer the header path everywhere you control the client.

Combine with throttling. The middleware does a database lookup per request; put throttle: in front of it so unauthenticated floods don't hit the api_keys table:

Route::group(['middleware' => ['throttle:60,1', 'auth.apikey']], function () { ... });

Whitelist noisy endpoints. Health checks, Stripe/ GitHub webhooks, and docs should skip the key check via the ignore list in config/apiguard.php rather than by splitting route files.

Testing. The middleware is a normal route middleware, so it runs in feature tests:

$key = ApiKey::generate($user->id);

$this->withHeader('X-Api-Key', $key->key)
     ->getJson('/api/v1/orders')
     ->assertOk();

$this->getJson('/api/v1/orders')->assertStatus(401);

Integration with existing auth. Treat API keys as an authentication layer and keep your authorization in policies/gates — the middleware only proves "who", not "what".

Gotchas and Tips

  • It's effectively unmaintained. Last release 2016-10-26. Pin the exact version, vendor the fork if you need PHP 8 / Laravel 9+ fixes (str_random, container bindings, Route:: signatures), and plan an exit. For new projects, Laravel Sanctum or a small custom middleware is a better bet.
  • Keys are stored in plaintext. You cannot show a key again from the DB safely, and any DB dump or log leak is a credential leak. At minimum, add a last_used_at/revoked_at column and never log the X-Api-Key header (many log formatters and APMs capture headers by default).
  • Keys in query strings leak. They land in access logs, browser history, and Referer. If you must use query_key, scrub it in your log middleware.
  • CORS preflight will 401. OPTIONS requests carry no X-Api-Key. Add OPTIONS handling (or the route) to the ignore list, otherwise browsers break before the real call.
  • Middleware ordering matters. Throttle before auth so brute-force attempts are cheap to reject; but if you need per-key rate limits you'll have to read the key yourself, since the package doesn't expose rate-limit primitives.
  • Proxies and headers. Load balancers and API gateways sometimes strip custom headers. Confirm X-Api-Key survives your stack (nginx underscores_in_headers is the classic trap if you rename it).
  • No expiry, rotation, or scopes out of the box. Add your own migration columns and extend the model, then wrap the middleware (or subclass it) to enforce expiry and scopes. Keeping a custom subclass, rather than editing vendor code, means you can still take a security patch if one ever ships.
  • The model is swappable via config. If you outgrow the default ApiKey, point the config at your own model — this is the cleanest extension point, and the one to use when migrating off the package (dual-read old keys, issue new ones, sunset).
  • Debugging 401s. In order: is the alias registered on the route group, is the key actually in the DB (ApiKey::where('key', $k)->exists()), is the header name in config the same one your client sends, and does the route appear in the ignore list unexpectedly?
  • Migration path. When replacing with Sanctum: issue personal access tokens to users in a batch job keyed off the existing api_keys rows, email/notify consumers, then swap the middleware alias globally — because every protected route already uses one alias, the cutover is a one-line change in Kernel.php.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core