Certainly! Here’s a step-by-step guide to set up Laravel 12 as an API backend using Sanctum SPA cookie authentication, suitable for a React (Axios & Vite) frontend. This will cover configuration, routes, and a basic AuthController for registration, login, and logout.
1. Install Sanctum
composer require laravel/sanctum
php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
php artisan migrate
2. Sanctum Middleware
In app/Http/Kernel.php, add Sanctum’s middleware to the api group:
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
3. Configure CORS
In config/cors.php:
'paths' => ['api/*', 'sanctum/csrf-cookie'],
'allowed_methods' => ['*'],
'allowed_origins' => ['http://localhost:5173'], // Vite default port
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
4. Configure Sanctum
In config/sanctum.php:
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,localhost:5173,127.0.0.1,127.0.0.1:5173')),
In .env:
SESSION_DOMAIN=localhost
SANCTUM_STATEFUL_DOMAINS=localhost,localhost:5173,127.0.0.1,127.0.0.1:5173
5. Set Session Driver
In .env:
SESSION_DRIVER=cookie
6. Routes
In routes/api.php:
use App\Http\Controllers\AuthController;
Route::post('/register', [AuthController::class, 'register']);
Route::post('/login', [AuthController::class, 'login']);
Route::get('/sanctum/csrf-cookie', function () {
return response()->noContent();
});
Route::middleware('auth:sanctum')->post('/logout', [AuthController::class, 'logout']);
7. AuthController Example
Generate controller:
php artisan make:controller AuthController
Then in app/Http/Controllers/AuthController.php:
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class AuthController extends Controller
{
public function register(Request $request)
{
$request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
'password' => 'required|string|min:8|confirmed',
]);
$user = User::create([
'name' => $request->name,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
Auth::login($user);
return response()->json(['message' => 'Registered successfully'], 201);
}
public function login(Request $request)
{
$request->validate([
'email' => 'required|email',
'password' => 'required',
]);
if (!Auth::attempt($request->only('email', 'password'), true)) {
return response()->json(['message' => 'Invalid credentials'], 401);
}
$request->session()->regenerate();
return response()->json(['message' => 'Logged in successfully']);
}
public function logout(Request $request)
{
Auth::guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return response()->json(['message' => 'Logged out successfully']);
}
}
8. Testing with Postman or Axios
Important:
- Always call
GET /sanctum/csrf-cookiefirst to set theXSRF-TOKENcookie. - For
POSTrequests (login, register, logout), send theX-XSRF-TOKENheader with the value from theXSRF-TOKENcookie. - Make sure to send cookies with your requests (
withCredentials: truein Axios, or enable cookies in Postman).
Example Axios config:
axios.defaults.withCredentials = true;
axios.get('http://localhost:8000/sanctum/csrf-cookie').then(() => {
axios.post('http://localhost:8000/api/login', {
email: '[email protected]',
password: 'password'
});
});
9. Common Issues
- 401 on logout:
This usually means the session cookie is not being sent. Make sure your frontend is sending cookies (withCredentials: true) and your CORS config allows credentials. - CSRF mismatch:
Always fetch/sanctum/csrf-cookiebefore making POST requests.
10. Summary
- Configure CORS and Sanctum for stateful SPA authentication.
- Use
auth:sanctummiddleware for protected routes. - Always fetch CSRF cookie before login/logout.
- Ensure cookies are sent with requests.
If you follow these steps, Sanctum SPA authentication should work with your React frontend and Laravel backend. If you still get 401 on logout, double-check that cookies are being sent and your CORS settings are correct.