Modern web systems must authenticate two distinct types of clients: Mobile & Third-Party Applications (which cannot store session cookies and require stateless Bearer API Tokens) and Single Page Applications (SPAs) like React, Vue, or Next.js (which should use secure, HttpOnly CSRF-protected session cookies). Laravel Sanctum is the official lightweight package designed specifically to solve both problems flawlessly.
Install and initialize Sanctum using the Artisan command:
# Install API tooling & Sanctum tables
php artisan install:api
# Run migrations to create personal_access_tokens table
php artisan migrate
Add the HasApiTokens trait to your app/Models/User.php model:
namespace App\Models;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use HasApiTokens; // Grants token issuance & inspection methods
}
Create an endpoint where mobile users exchange email and password for a long-lived Bearer API token:
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use App\Models\User;
use Illuminate\Validation\ValidationException;
Route::post('/api/v1/auth/token', function (Request $request) {
$request->validate([
'email' => 'required|email',
'password' => 'required',
'device_name' => 'required|string',
]);
$user = User::where('email', $request->email)->first();
if (!$user || !Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'email' => ['The provided credentials are incorrect.'],
]);
}
// Issue token with specific granular abilities (scopes)
$token = $user->createToken($request->device_name, ['articles:create', 'articles:read']);
return response()->json([
'token' => $token->plainTextToken,
'token_type' => 'Bearer',
'user' => $user,
]);
});
To protect your endpoints, assign the auth:sanctum middleware:
Route::middleware('auth:sanctum')->group(function () {
// Current authenticated user
Route::get('/api/v1/user', fn(Request $request) => $request->user());
// Checking token abilities
Route::post('/api/v1/articles', function (Request $request) {
if (!$request->user()->tokenCan('articles:create')) {
abort(403, 'Your API token lacks permission to publish articles.');
}
// Create article...
});
// Revoking current device token (Logout)
Route::post('/api/v1/auth/logout', function (Request $request) {
$request->user()->currentAccessToken()->delete();
return response()->json(['message' => 'Token revoked successfully.']);
});
});
For SPAs residing on the same top-level domain as your API (e.g. app.veewom.com communicating with api.veewom.com), Sanctum does not use tokens! Instead, your SPA makes a GET /sanctum/csrf-cookie call first, followed by a standard POST /login with cookies. This provides maximum security against XSS token theft.
Broaden your backend architecture, REST API design, and enterprise production engineering expertise:
Protect private API routes with the auth:sanctum middleware pipeline.
Return authenticated user profiles and tokens cleanly in JSON payloads.
Configure Sanctum token expiration timestamps and revoke stolen credentials.
Explain Sanctum SPA cookie authentication vs Passport OAuth2 in interviews.