In this 2026 guide, you’ll learn how to build a clean, secure API authentication system in Laravel 12 using Laravel Sanctum. We’ll cover installation, login & logout, protected routes, Postman testing, and best practices for modern APIs that power SPAs and mobile apps.
1. What Is Laravel Sanctum?
Laravel Sanctum is a lightweight authentication system for APIs, SPAs, mobile apps, and simple token-based login. It’s perfect in 2026 because it gives you secure token auth without the complexity of OAuth or Laravel Passport.
Sanctum is great when you want:
- Simple personal access tokens for your users
- Secure APIs for React / Vue / mobile apps
- Ability to create, revoke, and limit tokens
- First-class support inside modern Laravel
In simple terms: “Sanctum makes API authentication easy while still being secure and production-ready.”
2. Install Sanctum in Laravel 12 (2026)
First, install Sanctum via Composer:
composer require laravel/sanctum
Then publish the configuration and migrations:
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
After this, your database will have a personal_access_tokens table where Sanctum stores tokens for users.
3. Laravel 12 Middleware Setup (Important Update)
In Laravel 12 (and Laravel 11), the framework no longer uses app/Http/Kernel.php. Middleware configuration has moved to bootstrap/app.php.
This is a major architectural improvement—but here’s the good news:
If you are using Laravel Sanctum with token-based authentication (Authorisation: Bearer tokens), you do NOT need to add or modify any middleware manually.
Laravel Sanctum works out of the box for API authentication in Laravel 12. You simply protect your API routes using the auth:sanctum middleware.
✅ Laravel 12 Note
For token-based APIs (mobile apps, SPAs, Postman testing), Sanctum does not require any middleware configuration in bootstrap/app.php. Just use auth:sanctum on your routes.
This keeps your API authentication setup clean, minimal, and fully aligned with modern Laravel standards.
4. Enable Token Support in the User Model
Sanctum uses a trait called HasApiTokens on your User model to manage tokens.
Open app/Models/User.php and update it like this:
<?php
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
// ...
}
Now each user can have multiple personal access tokens (for example: web app, mobile app, admin panel, etc.).
5. Create Login API to Issue Tokens
Let’s build a dedicated API controller for authentication.
Generate a controller:
php artisan make:controller Api/AuthController
Now open app/Http/Controllers/Api/AuthController.php and add a login method:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
class AuthController extends Controller
{
public function login(Request $request)
{
// 1. Validate request
$request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
// 2. Find user by email
$user = User::where('email', $request->input('email'))->first();
// 3. Check if user exists and password matches
if (! $user || ! Hash::check($request->input('password'), $user->password)) {
return response()->json([
'message' => 'Invalid credentials',
], 401);
}
// 4. Create new personal access token
$token = $user->createToken('api_token')->plainTextToken;
// 5. Return token in JSON response
return response()->json([
'message' => 'Login successful',
'token' => $token,
'user' => $user,
]);
}
}
What this does:
- Validates email/password input
- Checks the credentials against the database
- Creates a new Sanctum token using
createToken() - Returns the token (and user) as JSON
Your frontend or mobile app will store this token (for example, in localStorage or secure mobile storage) and send it on all future API calls.
6. Logout API — Revoke the Current Token
For logout, we want to delete the current token so that it can’t be used anymore.
Add this inside the same AuthController:
public function logout(Request $request)
{
// Delete the token that was used to authenticate the current request
$request->user()?->currentAccessToken()?->delete();
return response()->json([
'message' => 'Logged out successfully',
]);
}
This doesn’t delete all tokens for the user—only the one used in the current API call. That’s ideal when a user has multiple logged-in devices.
7. Protecting API Routes with Sanctum
Open your routes/api.php file and wire up the auth routes:
<?php
use App\Http\Controllers\Api\AuthController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::post('/login', [AuthController::class, 'login']);
// Routes that require authentication
Route::middleware('auth:sanctum')->group(function () {
Route::post('/logout', [AuthController::class, 'logout']);
Route::get('/user', function (Request $request) {
return $request->user();
});
// Example protected endpoint
Route::get('/dashboard-stats', function () {
return [
'visits' => 1234,
'sales' => 57,
];
});
});
Any route inside the Route::middleware('auth:sanctum') group requires a valid token. The client must send the token like this:
GET /api/user HTTP/1.1
Host: your-app.test
Authorization: Bearer 1|exampleapitokenstring...
Accept: application/json
8. Testing Sanctum with Postman in 2026
Let’s test your API step by step using Postman (or any API client).
8.1 Login and Get Token
- Open Postman and create a new POST request to
/api/login. - Set the request body type to JSON.
- Use a payload like this:
{
"email": "test@example.com",
"password": "password"
}
If the user exists and the password is correct, you’ll get a response like:
{
"message": "Login successful",
"token": "1|abc123verylongapitoken...",
"user": {
"id": 1,
"name": "Test User",
"email": "test@example.com",
"created_at": "2026-01-01T10:00:00.000000Z",
"updated_at": "2026-01-01T10:00:00.000000Z"
}
}
8.2 Call a Protected Route
- Copy the
tokenvalue from the login response. - Create a new GET request to
/api/user(or any protected route). - In the Headers tab, add:
Authorization: Bearer 1|abc123verylongapitoken...
Accept: application/json
If everything is set up correctly, the API will return the authenticated user’s details instead of Unauthenticated.
8.3 Logout
- Create a POST request to
/api/logout. - Use the same
Authorization: Bearer <token>header.
Response example:
{
"message": "Logged out successfully"
}
After this, using the same token again should result in a 401 Unauthenticated response.
9. Common Sanctum Issues and Fixes
9.1 “Unauthenticated.”
Cause: The Authorization header is missing or incorrect.
Fix: Always send the header like this:
Authorization: Bearer <your_token_here>
Also check that your API routes are using auth:sanctum and that the token has not been deleted.
9.2 CORS / SPA Problems
If you’re calling the API from a different domain (like a React frontend), you might see CORS errors.
In config/cors.php, you can expose the Authorization header:
'exposed_headers' => ['Authorization'],
Also ensure your allowed_origins or allowed_origins_patterns are correctly configured for your frontend domain.
9.3 Token Works in Postman but Not in Frontend
Possible causes:
- Frontend is not sending the Authorization header correctly
- Token is being stripped or modified by a proxy
- You’re mixing cookies + tokens incorrectly
In 2026, a common pattern is: use Bearer tokens in the Authorization header for SPAs and mobile apps, and use cookies with CSRF for classic server-rendered apps.
10. Best Practices for Sanctum in 2026
10.1 Use Short-Lived Tokens Where Possible
Sanctum tokens don’t expire by default. You can implement your own expiry logic or rotate tokens periodically (for example, regenerate a token every few weeks and revoke the old ones).
10.2 Use Token Abilities
Abilities are like simple “scopes” for tokens. For example, you can issue a token that can only read data but not write.
$token = $user->createToken('mobile_app', ['read', 'write'])->plainTextToken;
Then in your code, you can check:
if ($request->user()->tokenCan('write')) {
// allow write actions
}
10.3 Always Use HTTPS in Production
Never send API tokens over plain HTTP. Use HTTPS in production so that your tokens are encrypted in transit.
10.4 Revoke Tokens on Logout and When Compromised
Whenever a user logs out, loses a device, or reports suspicious activity, revoke their tokens. You can delete one token or all tokens for that user:
// Delete ALL tokens for a user
$user->tokens()->delete();
11. Conclusion
In this 2026 guide, you learned how to set up Laravel 12 Sanctum API authentication step by step:
- Installing Sanctum and running migrations
- Adding the Sanctum middleware and
HasApiTokenstrait - Building login and logout API endpoints
- Protecting routes with
auth:sanctum - Testing everything with Postman
- Handling common errors and following best practices
Sanctum gives you a clean, modern way to secure APIs for SPAs, mobile apps, and microservices without the overhead of full OAuth.
From here, you can:
- Integrate this API with a Vue / React or Livewire frontend
- Build separate tokens for mobile apps and admin dashboards
- Add role-based permissions on top of Sanctum
If you enjoyed this tutorial, you might also like: