6 min read
Delivery Manager & Software Architect

Most Laravel Sanctum tutorials hand you a createToken() snippet and call it authentication. Then you wire it into a React or Vue frontend on the same domain, and you have quietly built the wrong thing - Sanctum's own docs tell you not to use API tokens to authenticate your own first-party SPA.
We run Sanctum in production across our own SaaS backends - including a multi-tenant platform where users live on per-tenant subdomains, and an internal tool that mints Sanctum tokens against a non-User model and rotates them on a schedule. The single decision that determines whether Sanctum is effortless or a week of CORS debugging is the one most guides skip: which of Sanctum's two modes you actually need.
This guide leads with that, then gives you the current, correct setup for each.
Here are some of the standout features of Laravel Sanctum that highlight why you should consider using this tool to simplify authentication.
Sanctum allows users to issue API tokens without the complexity of OAuth. These tokens can be scoped, restricting the actions they can perform. This is particularly useful for managing API access for different parts of your application or for external services.
For SPAs, Sanctum uses cookie-based session authentication, which allows your JavaScript front end to authenticate using the same Laravel session cookies. This approach provides a seamless and secure authentication mechanism for SPAs.
Sanctum offers robust CSRF protection for your application. When using Sanctum, your API requests are protected against CSRF attacks, ensuring the security of your application.
On Laravel 11, 12, and 13 there is a single Artisan command that installs Sanctum, publishes its config, and adds the migration:
php artisan install:api
Run your migrations, and Sanctum is ready. If you are authenticating an SPA, also complete the SPA configuration section below.
To issue a token to a user, first, you need to update the User model:
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
Creating token:
$token = $request->user()->createToken($request->token_name);
return ['token' => $token->plainTextToken];
Revoking tokens:
// Revoke all tokens...
$user->tokens()->delete();
// Revoke the token that was used to authenticate the current request...
$request->user()->currentAccessToken()->delete();
// Revoke a specific token...
$user->tokens()->where('id', $tokenId)->delete();
Tokens can have scopes that define their permissions. When creating a token, you can specify the scopes:
$token = $user->createToken('token-name', ['view-posts', 'create-posts'])
->plainTextToken;
You can then check the token’s scopes in your routes or controllers:
if ($user->tokenCan('create-posts')) {
// ...
}
Sanctum provides powerful middleware to check incoming requests if it is authenticated and have the token ability:
use Laravel\Sanctum\Http\Middleware\CheckAbilities;
use Laravel\Sanctum\Http\Middleware\CheckForAnyAbility;
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'abilities' => CheckAbilities::class,
'ability' => CheckForAnyAbility::class,
]);
})
To protect routes, you should use the auth:sanctum and ability (abilities) middleware:
Route::middleware(['auth:sanctum', 'abilities: create-post'])
->post('/posts/create', function (Request $request) {
//
});
The difference between ability and abilities is quite simple:
For SPAs, you need to set up session-based authentication. Typically, you will have a login route that your SPA will use to authenticate:
Route::post('/login', function (Request $request) {
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
$request->session()->regenerate();
return response()->json(['message' => 'Logged in successfully']);
}
return response()->json(['message' => 'Invalid credentials'], 401);
});
After logging in, your SPA can make authenticated requests using the session cookie.
When issuing a request for the sanctum route, first, you need to make a request on /sanctum/csrf-cookie to init CSRF protection:
axios.get('/sanctum/csrf-cookie').then(response => {
axios.post('/login', {
email: 'user@example.com',
password: 'password'
}).then(response => {
// Handle successful authentication
}).catch(error => {
// Handle authentication failure
});
});
When SPA auth "just returns 401/419 and no one knows why," it is almost always one of these, and we have hit each in real Redberry projects.
supports_credentials is false, or the SPA origin is not instateful, or the session domain is missing its leading dot, the browser silently drops the cookie, and every request looks logged out. Change all four together, then clear cookies before retesting.X-XSRF-TOKEN header is missing or not URL-decoded - you skipped the /sanctum/csrf-cookie call or withXSRFToken is off.domain must cover the parent (.example.com) or a tenant cannot stay logged in across its own subdomain. We ship exactly this pattern in production, and it is invisible until it breaks.[VERIFY] behavior against your Octane + Sanctum versions.User model: HasApiTokens works on any Eloquent model, not just User. We mint Sanctum tokens on a repository/integration model and rotate them, leaning on Sanctum's expires_at to keep the old token valid during a short grace-period overlap so nothing breaks mid-rotation. [VERIFY] Exact Sanctum major version that introduced native expires_at.Authenticate a fake user (with abilities) in tests without minting a real token:
use Laravel\Sanctum\Sanctum;
Sanctum::actingAs(User::factory()->create(), ['view-tasks']);
// use ['*'] to grant all abilities
Laravel Sanctum provides a simple yet powerful solution for API token management and SPA authentication. Its ease of use, combined with Laravel’s robust features, makes it an excellent choice for developers looking to implement secure authentication mechanisms. It doesn’t matter whether you’re building an API, a mobile app, or a SPA; Laravel Sanctum offers the flexibility and simplicity you need to manage authentication effectively.
Konstantine (Kosta) is a Software Architect at Redberry with over a decade of experience in PHP, Laravel, TypeScript, and Vue.js. He owns architecture and tooling decisions across the team, with hands-on backend delivery. He's architected platforms including CapGain, an investor management system for Arboris Capital, and leads Redberry's work on Tavistock's finance-automation and wealth tech products.
Last updated on by

Redberry tops Clutch's Top 15 Laravel Developers list in the 2026 Clutch Global Awards - several years running.
Redberry is a sponsor of Laravel Live Denmark 2026, held August 20-21 at Werkstatt on Reffen in Copenhagen - the first year we have sponsored this event. Two of us will be there for it: Gaga Darsalia, our CEO, and Dati Chkhikvishvili, our Chief of Business.
At Laracon US 2026 our CEO Gaga Darsalia sat down with Eric Barnes of Laravel News to talk regulated fintech, AI-led legacy modernization, and why Redberry keeps coming back to Laracon.

We are a 200+ people agency and provide product design, software development, and creative growth marketing services to companies ranging from fresh startups to established enterprises. Our work has earned us 100+ international awards, partnerships with Laravel, Vue, Meta, and Google, and the title of Georgia’s agency of the year in 2019 and 2021.

