Laravel Sanctum is de eenvoudigste manier om authenticatie aan een moderne API toe te voegen. Zonder de complexiteit van JWT-bibliotheken of de zware opzet van OAuth lost het twee behoeften op in één pakket: API-tokens voor mobiele apps en externe clients, en cookiegebaseerde sessies voor SPA's zoals React of Vue die op hetzelfde domein draaien. In dit artikel zetten we beide benaderingen op met echte, werkende code.
Wanneer en waarom Sanctum?
Het Laravel-ecosysteem biedt drie belangrijke authenticatieopties: Passport voor projecten die een volledige OAuth2-server nodig hebben, externe bibliotheken voor stateless JWT's, en Sanctum, de lichtgewicht oplossing die de meeste applicaties daadwerkelijk nodig hebben. Sanctum is de juiste keuze als je je in een van deze situaties bevindt:
- Je hebt een mobiele app of CLI-tool en wilt een eenvoudige
Bearer-token aan elk verzoek toevoegen. - Je frontend (SPA) draait op hetzelfde hoofddomein als je Laravel-API en je hebt geen echte OAuth-flow nodig.
- Je wilt tokens permissies op basis van capaciteiten (abilities) geven — bijvoorbeeld een token dat alleen mag lezen.
Als je een platform bouwt dat openstaat voor externe ontwikkelaars en OAuth2-flows vereist (authorization code, client credentials), past Passport beter. Voor de meeste praktische scenario's is Sanctum echter sneller op te zetten en vereist het minder onderhoud.
Installatie
In Laravel 11 en 12 komt Sanctum in één stap via het commando install:api. Dit commando publiceert het pakket, voegt de migratie toe en bereidt het API-routebestand voor:
php artisan install:api
Nadat het commando is uitgevoerd, zijn de migraties al gedraaid en is de tabel personal_access_tokens aangemaakt. Je hoeft alleen de HasApiTokens-trait aan je user-model toe te voegen:
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
Deze trait geeft het model de methode createToken() en de relatie tokens(). We kunnen nu tokens uitgeven.
API-tokens uitgeven en gebruiken
Het meest voorkomende scenario: een gebruiker logt in met e-mail en wachtwoord, en jij stuurt een token terug. De client slaat deze op en stuurt hem bij volgende verzoeken mee via de header Authorization: Bearer <token>. Een eenvoudige login-controller ziet er zo uit:
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Hash;
use App\Models\User;
public function login(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' => ['De opgegeven gegevens zijn onjuist.'],
]);
}
$token = $user->createToken('mobiele-app')->plainTextToken;
return response()->json(['token' => $token]);
}
Er is hier een belangrijk detail: plainTextToken geeft de leesbare waarde van de token alleen op het moment dat hij wordt aangemaakt terug. De database slaat enkel een hash van de token op, dus als je deze waarde kwijtraakt kun je hem niet meer herstellen — de client moet hem direct opslaan.
Bescherm je routes met de auth:sanctum-middleware. In routes/api.php:
use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Aan de clientkant ziet het verzoek er zo uit:
curl https://api.voorbeeld.com/api/user \
-H "Authorization: Bearer 1|abcDEF..." \
-H "Accept: application/json"
Token-capaciteiten (abilities)
Sanctum laat je specifieke capaciteiten aan elke token toewijzen. Dit is een nette manier om te beperken wat een token mag doen:
$token = $user->createToken('rapport-bot', ['post:read'])->plainTextToken;
In een controller of route kun je deze capaciteit controleren:
if ($request->user()->tokenCan('post:read')) {
// heeft leesrechten
}
Je kunt ook de middlewares abilities en ability aan routes toevoegen om toegang op poortniveau te beperken. Onthoud dat capaciteiten slechts een gemakslaag zijn; je moet de echte autorisatielogica nog steeds in je applicatie afdwingen.
SPA-authenticatie
Voor een SPA die op hetzelfde hoofddomein draait, gebruikt Sanctum de sessiecookies van Laravel in plaats van tokens. Deze aanpak is veiliger omdat je de token niet in localStorage hoeft te bewaren, waar JavaScript bij kan; de browser beheert de HttpOnly-cookie automatisch. De flow is als volgt:
- De SPA vraagt eerst een CSRF-cookie aan via het eindpunt
/sanctum/csrf-cookie. - Vervolgens stuurt hij een normaal webverzoek naar de route
/login; bij succes wordt een sessiecookie ingesteld. - Alle volgende API-verzoeken komen al geauthenticeerd binnen via die cookie.
Drie instellingen zijn hierbij belangrijk. Zet eerst supports_credentials op true in config/cors.php. Registreer ten tweede het domein van je SPA in het .env-bestand:
SANCTUM_STATEFUL_DOMAINS=localhost:3000
SESSION_DOMAIN=localhost
Ten derde moet de client cookies met zijn verzoeken meesturen. Als je Axios gebruikt:
import axios from 'axios';
axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;
await axios.get('/sanctum/csrf-cookie');
await axios.post('/login', { email, password });
const { data } = await axios.get('/api/user');
De meest gemaakte fout hier is de SPA en de API op compleet verschillende domeinen draaien en je dan afvragen waarom de sessie niet blijft hangen. De cookiegebaseerde methode vereist dat beide hetzelfde hoofddomein delen (bijvoorbeeld app.voorbeeld.com en api.voorbeeld.com).
Tokens intrekken en beveiliging
Wanneer een gebruiker uitlogt of een apparaat verliest, moet je tokens ongeldig maken. Om de huidige token te verwijderen:
$request->user()->currentAccessToken()->delete();
Om alle tokens in te trekken (overal uitloggen):
$request->user()->tokens()->delete();
Een paar beveiligingsnotities: stel een vervaltijd voor tokens in via config/sanctum.php (de sleutel expiration), draai je API altijd achter HTTPS, en voeg de throttle-middleware toe aan je login-eindpunt om brute-force-pogingen te beperken. Aan de SPA-kant is actieve CSRF-bescherming het grootste voordeel dat de cookiegebaseerde methode biedt.
Veelgestelde vragen
Moet ik Sanctum of Passport gebruiken?
Tenzij je een volledige OAuth2-server bouwt die openstaat voor externe ontwikkelaars, kies je Sanctum. Voor mobiele-app-tokens en eigen SPA-sessies is Sanctum zowel lichter als makkelijker te onderhouden. Passport is zinvol wanneer je OAuth-flows zoals de authorization code grant nodig hebt.
Waar moet ik tokens opslaan?
Bewaar in mobiele apps de token in de beveiligde opslag van het platform (iOS Keychain, Android Keystore). Gebruik in SPA's cookiegebaseerde SPA-authenticatie in plaats van de tokenmethode, zodat je de token niet in localStorage hoeft te bewaren waar JavaScript bij kan.
Waarom geeft mijn SPA-login een 419-fout?
Een 419-fout is meestal een CSRF-token-mismatch. Zorg ervoor dat je /sanctum/csrf-cookie aanroept vóór je verzoeken, dat de client cookies meestuurt (withCredentials), en dat SANCTUM_STATEFUL_DOMAINS en SESSION_DOMAIN correct zijn ingesteld.
Wil je een veilige authenticatielaag voor je API opzetten? Als je hulp nodig hebt bij Laravel Sanctum-integratie, SPA-sessies of je mobiele API's, neem contact met me op — laten we samen de oplossing bouwen die het beste bij jouw project past.