ryangjchandler/bearer
A lightweight Laravel package for issuing and authenticating bearer tokens, letting you protect API routes with token abilities and expiration—no full OAuth setup required.
ryangjchandler/bearer is a lightweight bearer-token authentication layer for Laravel — closer to "Sanctum's token API without the SPA/session machinery" than to Passport. v2.1.1 is a compatibility-only patch (adds Laravel 13.x to the constraint), so it changes nothing about how you use it.
Minimal setup:
composer require ryangjchandler/bearer
php artisan vendor:publish --tag=bearer-config # check the tag in the README first
php artisan migrate # only if your config uses DB-backed tokens
First places to look:
config/bearer.php — this is where the token model/table, hashing, and any expiry settings live. Read it before writing a single line of auth code; most confusion about this package comes from assuming defaults that live here.Bearer facade — the public extension surface (authenticateUsing, token creation/lookup hooks). Treat this as the package's real API; the config is mostly data.routes/api.php — the middleware is where the package actually enters the request lifecycle.First use case: issue a token at login, send it as Authorization: Bearer <token>, protect a route group with the package's middleware alias (bearer), and resolve the user with $request->user() exactly as you would with any other guard. If $request->user() is null inside the group, the middleware isn't applied or is ordered after something that short-circuits — see Gotchas.
Issue tokens at a single choke point. Put creation in one action/service (IssueToken) rather than in each controller. Return the plaintext token exactly once in the response, persist only what the package stores, and never re-emit it from a "list my tokens" endpoint.
Group, don't sprinkle. Apply the middleware to the whole API group in bootstrap/app.php (Laravel 11+) or Kernel.php (10.x), then opt individual routes out with ->withoutMiddleware(...) where you need public access. Per-route middleware is the fastest way to end up with one unprotected endpoint.
Abilities/scopes over role checks. If you're using token abilities, gate at the route layer (middleware('bearer:posts:write') or an ability-check middleware) rather than scattering if statements in controllers. Keep the ability string list in a PHP enum so issuance and checking can't drift apart.
Custom resolution closure. The most common real-world pattern is overriding user resolution so you can enforce things the package can't know about — tenant scoping, a revoked_at column, a plan downgrade, a soft-deleted user:
Bearer::authenticateUsing(function ($request, $token) {
$user = User::whereKey($token->user_id)->whereNull('suspended_at')->first();
abort_unless($user, 401);
return $user;
});
Register this in a service provider, not in a controller — it's global state and must be deterministic.
Coexistence with Sanctum. It's common to keep Sanctum for first-party SPA sessions and use Bearer for machine clients. If you do, be explicit per route group which guard applies; two token systems resolving $request->user() with different auth guards is the top source of "wrong user" bugs.
Testing. Hit the real middleware in feature tests with a real header — $this->withHeader('Authorization', "Bearer {$token}") — rather than actingAs(). actingAs() bypasses the package's token lookup entirely and will let a broken token path ship green.
^2.1 and take the patch anyway — there are no behavioural changes, so it's a zero-risk bump. Do check that your other auth packages (Sanctum/Passport) already allow Laravel 13 before upgrading the framework itself; that's the real blocker, not this release.bearer, it will reject the request before the token is ever read. The bearer middleware must run before anything that calls $request->user() or auth()->user().php artisan config:cache in deploy will freeze config/bearer.php. If you change token settings and behaviour doesn't move, that's almost always why — config:clear locally, and re-run the cache step in CI.last_used_at-style writes. If your config/model touches the token row on every request, you've turned every read endpoint into a write. Either disable it or debounce it (cache a "touched recently" flag) before this becomes your database's hottest table.queue:restart) after deploying auth changes, and be careful with any per-request user caching under Octane.Bearer prefix), middleware presence on the route (php artisan route:list -v), then the resolution closure (temporarily Log::info the token lookup result). That covers ~95% of cases.How can I help you explore Laravel packages today?