laravel/airlock
Laravel Sanctum (formerly Airlock) offers lightweight authentication for Laravel SPAs and simple APIs. Use cookie-based session auth for first-party SPAs or issue API tokens for mobile apps and third-party clients, with minimal setup and seamless Laravel integration.
Installation:
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
Add Sanctum\HasApiTokens to your User model and Authenticate middleware to api.php.
First Use Case:
$user = User::find(1);
$token = $user->createToken('api-token')->plainTextToken;
Authorization: Bearer {token}
Key Files:
config/sanctum.php: Configuration for stateful domains, token expiration, and middleware.app/Models/User.php: Ensure HasApiTokens is included.routes/api.php: Define Sanctum routes (e.g., Sanctum::routes()).Token Generation & Management:
$token = $user->createToken('auth-token', ['read', 'write']);
$user->tokens()->where('name', 'auth-token')->delete();
if ($request->user()->tokenCan('read')) { ... }
Stateful API (SPA) Workflow:
config/sanctum.php:
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,127.0.0.1')),
Sanctum::actingAs($user) in middleware to simulate authenticated requests.Custom Token Logic:
HasApiTokens for custom token behavior:
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens;
public function createCustomToken($name)
{
return $this->createToken($name, ['custom:scope']);
}
}
Middleware Integration:
Route::middleware(['auth:sanctum'])->group(function () {
// Protected routes
});
Sanctum::getAccessTokenFromRequestUsing(function ($request) {
return $request->bearerToken() ?: $request->cookie('sanctum');
});
Testing:
actingAs in tests:
$response = $this->actingAs($user)->get('/api/user');
$this->withHeaders(['Authorization' => 'Bearer ' . $token]);
Frontend-Specific:
axios with Sanctum’s CSRF cookie:
axios.get('/sanctum/csrf-cookie');
axios.get('/api/user', { withCredentials: true });
config/cors.php to allow credentials.Multi-Guard Support:
'guards' => [
'web' => ['driver' => 'session'],
'api' => ['driver' => 'sanctum', 'provider' => 'users'],
],
Token Expiration:
config/sanctum.php:
'expiration' => now()->addDays(15),
php artisan sanctum:prune
Database Optimization:
personal_access_tokens table for large-scale apps:
Schema::table('personal_access_tokens', function (Blueprint $table) {
$table->index(['tokenable_id', 'tokenable_type']);
$table->index('created_at');
});
CSRF Token Issues:
XSRF-TOKEN cookie is set for stateful requests. Use:
Sanctum::csrfCookie();
php artisan sanctum:check
Token Not Found:
expires_at column.$token = $user->tokens()->where('name', 'token-name')->first();
Stateful Domain Mismatch:
api.yourapp.com) won’t receive CSRF cookies. Configure explicitly:
'stateful' => ['localhost', 'yourapp.test', 'api.yourapp.com'],
Middleware Order:
auth:sanctum after EnsureFrontendRequestsAreStateful in api.php:
Route::middleware(['throttle:api', 'auth:sanctum'])->group(...);
Token Length:
createToken method or use Str::random(80).Log Token Activity:
last_used_at tracking in config/sanctum.php:
'track_last_used_at' => true,
$token->last_used_at; // Last activity timestamp
Check Token Validity:
if (Sanctum::validateToken($token, $user)) { ... }
Database Queries:
where('id', $tokenId) (use where('token', $token) instead).Environment Issues:
APP_URL and SANCTUM_STATEFUL_DOMAINS match your frontend’s origin. Test with:
php artisan sanctum:check
Custom Token Model:
Laravel\Sanctum\PersonalAccessToken for custom logic:
class CustomToken extends PersonalAccessToken
{
public function customMethod()
{
return $this->tokenable->name;
}
}
config/sanctum.php:
'token_model' => \App\Models\CustomToken::class,
Override Token Creation:
User model:
public function createToken($name, array $abilities = [])
{
return parent::createToken($name, $abilities)->tap(function ($token) {
$token->abilities = serialize($abilities);
});
}
Event Listeners:
Creating, Revoked):
use Laravel\Sanctum\Events\TokenCreated;
TokenCreated::listen(function (TokenCreated $event) {
Log::info("Token created for {$event->token->tokenable->name}");
});
API Resource Extensions:
public function toArray($request)
{
return [
'id' => $this->id,
'tokens' => $this->tokens()->get()->map(fn ($token) => [
'name' => $token->name,
'abilities' => $token->abilities,
]),
];
}
encrypt_cookies:
false for performance (but lose security):
'encrypt_cookies' => env('SANCTUM_ENCRYPT_COOKIES', false),
prefix:
'prefix' => env('SANCTUM_PREFIX', null),
stateful Domains:
'stateful' => ['*.yourdomain.com'],
token_blacklist_enabled:
laravel/framework v9.2+):
'token_blacklist_enabled' => true,
How can I help you explore Laravel packages today?