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

Laravel Keyable Laravel Package

givebutter/laravel-keyable

Givebutter's Laravel Keyable brings simple, secure API key authentication to Laravel apps. Add the HasApiKeys trait to any model, generate and hash keys, protect routes with middleware, and manage multiple keys per user with straightforward revocation and expiration.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require givebutter/laravel-keyable
php artisan vendor:publish --tag="keyable-config"
php artisan vendor:publish --tag="keyable-migrations"
php artisan migrate
  1. Add the package's Keyable trait (and contract, if you want type-hinting) to any model that should be able to authenticate — usually App\Models\User.
  2. Register a guard in config/auth.php using the package's driver, pointing at your existing provider:
    'guards' => [
        'api' => ['driver' => 'keyable', 'provider' => 'users'],
    ],
    
  3. Issue a key from tinker or a console command: $user->generateKey('cli') (or the package's keyable:generate command). Copy the plaintext value — this is the only time you'll see it.
  4. Protect routes with the guard: Route::middleware('auth:api')->get('/user', fn () => request()->user()); and send Authorization: Bearer <key>.

First real use case: an internal/service-to-service API where you don't want a full OAuth/Sanctum token flow — generate one key per integration, name it, and revoke it independently.

Implementation Patterns

Per-integration keys, not per-user keys. Call generateKey() with a descriptive name ('zapier', 'mobile-ios') so $user->keys() gives you a revocable inventory. Rotate by creating a new key, shipping it, then deleting the old one — no user-visible downtime.

Auth is just a guard, so compose normally. auth:api plays fine with policies, gates, $request->user(), and RateLimiter::for('api', fn ($r) => Limit::perMinute(60)->by($r->user()?->id ?: $r->ip())). Put auth:api before throttle:api in the middleware stack so throttling can key off the authenticated model.

Use the new KeyableAuthenticated event (v3.1.1) as your audit hook. It fires on successful key auth, which is the right seam for:

  • recording last_used_at / IP / user-agent on the ApiKey record,
  • emitting metrics or Slack alerts on first use of a new key (detect leaked/abused keys),
  • pushing usage into a per-key rate limiter or billing counter,
  • broadcasting "key used" for a security dashboard.
Event::listen(KeyableAuthenticated::class, function ($event) {
    $event->key?->forceFill(['last_used_at' => now(), 'last_used_ip' => request()->ip()])->save();
});

Keep listeners ShouldQueue if they touch the network — this runs on every authenticated request.

Testing. Generate a key in a factory or test setup and hit routes with $this->withHeader('Authorization', "Bearer {$key}"). Assert 401 for a revoked/expired key by deleting or expiring the model before the request.

Provisioning. Wrap key creation in an artisan command or Filament/Nova action so keys are never generated by hand in production tinker; log the plaintext to a secure channel the user can read once.

Gotchas and Tips

  • The plaintext key is one-shot. Capture it at generation time; anything you read back out of the DB later isn't usable as a credential. Don't build an admin list view that tries to display existing keys.
  • Query-string auth is a leak vector. If the package accepts ?api_key=, it will end up in access logs, Referer headers, and error trackers. Restrict clients to the Authorization header, or strip the param at your edge proxy.
  • Config caching. Changing the guard driver or publishing/editing keyable.php requires php artisan config:cache (or config:clear) — a stale cached config is the usual cause of "guard [api] is not defined."
  • Guard collisions. If you already use Sanctum, keep auth:sanctum and auth:api on separate route groups; combining them in one auth:sanctum,api middleware means either credential works, which is rarely what you intend.
  • Expiry and revocation are your responsibility. Decide early whether keys expire, and add a scheduled command that prunes stale keys — an unbounded api_keys table with forever-valid keys is the classic failure mode.
  • The event only fires on success. Failed attempts (bad/expired key) won't hit KeyableAuthenticated, so pair it with Laravel's Illuminate\Auth\Events\Failed or middleware-level logging if you need brute-force detection.
  • Extension points: the published config for header/param names and key length, the Keyable trait's key-generation method (override in your model if you need a custom prefix or entropy source), and the event listener for post-auth side effects.
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.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource