Why Sanctum for API Auth
Sanctum provides lightweight token-based authentication ideal for SPAs, mobile apps, and simple token-based APIs, without the complexity of a full OAuth2 server that Passport requires.
Installation
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
Configuring the User Model
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
Login Endpoint Issuing Tokens
Route::post('/login', function (Request $request) {
$request->validate([
'email' => 'required|email',
'password' => 'required',
]);
$user = User::where('email', $request->email)->first();
if (!$user || !Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
$token = $user->createToken('api-token', ['orders:read'])->plainTextToken;
return response()->json(['token' => $token]);
});
Protecting Routes
Route::middleware('auth:sanctum')->group(function () {
Route::get('/user', fn (Request $request) => $request->user());
Route::apiResource('orders', OrderController::class);
});
Scoping Tokens with Abilities
// Restrict a token to read-only order access
$token = $user->createToken('mobile-app', ['orders:read'])->plainTextToken;
// Check ability inside a controller
public function destroy(Request $request, Order $order)
{
if (!$request->user()->tokenCan('orders:delete')) {
abort(403);
}
$order->delete();
}
API Resource Formatting
class OrderResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'total' => $this->total,
'status' => $this->status,
'items' => OrderItemResource::collection($this->whenLoaded('items')),
];
}
}
Revoking Tokens on Logout
Route::post('/logout', function (Request $request) {
$request->user()->currentAccessToken()->delete();
return response()->json(['message' => 'Logged out']);
})->middleware('auth:sanctum');
Conclusion
Sanctum strikes a good balance between simplicity and real security for most API use cases, especially first-party SPAs and mobile apps. Reach for Passport only if you actually need full OAuth2 flows for third-party integrations.