Laravel Sanctum vs Passport — API authenticatie voor e-commerce
Terug naar blog

Laravel Sanctum vs Passport — API authenticatie voor e-commerce

AuthorRuthger Idema
14 april 20269 min leestijd

Sanctum of Passport? De keuze hangt niet af van wat je mooi vindt. Het hangt af van wie je API gebruikt: een SPA, een mobiele app of een extern systeem met OAuth2 scopes.

Laravel Sanctum vs Passport — API authenticatie voor e-commerce

De vraag die wij het vaakst krijgen bij nieuwe Laravel API projecten: Sanctum of Passport? Het antwoord is niet welke je leuker vindt. Het antwoord is welke clients jouw API gebruiken en wat zij nodig hebben.

De meeste e-commerce projecten gebruiken Sanctum. Maar er zijn concrete situaties waar Passport de enige juiste keuze is. Dit artikel legt het verschil uit aan de hand van echte use cases.

Wat je leert in dit artikel

  • Hoe Sanctum werkt: token authenticatie en SPA authenticatie
  • Hoe Passport werkt: OAuth 2.0 volledig geïmplementeerd
  • Wanneer Sanctum voldoende is — en wanneer het dat niet is
  • Mobiele apps, SPA's en machine-to-machine: welk pakket past waar
  • Concrete implementaties voor e-commerce scenarios

Sanctum: lichtgewicht en snel

Sanctum geeft je twee dingen: API token authenticatie voor mobiele apps en server-to-server integraties, en cookie-gebaseerde SPA authenticatie voor Vue of React frontends op hetzelfde domein.

API tokens

Elke gebruiker kan meerdere tokens aanmaken. Elk token kan specifieke scopes (abilities) hebben.

php
// Token aanmaken bij login
class AuthController extends Controller
{
    public function login(Request $request): JsonResponse
    {
        $credentials = $request->validate([
            'email'    => ['required', 'email'],
            'password' => ['required'],
        ]);

        if (! Auth::attempt($credentials)) {
            return response()->json([
                'error' => ['code' => 'INVALID_CREDENTIALS', 'message' => 'E-mailadres of wachtwoord onjuist.'],
            ], 401);
        }

        $user = Auth::user();

        // Verwijder oude tokens (optioneel — voor mobiele apps gewenst)
        $user->tokens()->where('name', 'mobile-app')->delete();

        $token = $user->createToken('mobile-app', [
            'orders:read',
            'orders:create',
            'profile:read',
            'profile:update',
        ]);

        return response()->json([
            'token' => $token->plainTextToken,
            'user'  => new UserResource($user),
        ]);
    }
}
php
// Routes beveiligen met Sanctum
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/orders', [OrderController::class, 'index']);

    // Scope check: gebruiker moet 'orders:create' ability hebben
    Route::post('/orders', function (Request $request) {
        if (! $request->user()->tokenCan('orders:create')) {
            abort(403, 'Token heeft niet de juiste rechten.');
        }

        // Verwerk order...
    });
});

SPA authenticatie met cookies

Voor een Vue of React frontend op hetzelfde domein (of subdomain) gebruikt Sanctum session cookies in plaats van tokens. De browser beheert de cookie automatisch.

php
// config/sanctum.php
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
    Sanctum::currentApplicationUrlWithPort()
))),
javascript
// Frontend: eerst CSRF cookie ophalen
await axios.get('/sanctum/csrf-cookie');

// Daarna inloggen
const response = await axios.post('/login', {
    email: '[email protected]',
    password: 'wachtwoord',
});

// Alle volgende requests zijn automatisch geauthenticeerd via cookie
const orders = await axios.get('/api/v1/orders');

Dit werkt alleen als de frontend en backend op hetzelfde domein of een subdomain draaien. app.jouwshop.nl en api.jouwshop.nl werken. jouwshop.nl en partner-app.nl werken niet.

Passport: volledige OAuth 2.0

Passport implementeert de volledige OAuth 2.0 specificatie. Dat brengt meer mogelijkheden, maar ook meer complexiteit.

De vier OAuth 2.0 flows die Passport ondersteunt:

FlowWanneer gebruiken
Authorization CodeGebruiker autoriseert een externe app
Client CredentialsMachine-to-machine zonder gebruiker
Password GrantEigen apps met directe inlog (verouderd)
Implicit GrantVerouderd, gebruik Authorization Code met PKCE

Client Credentials voor machine-to-machine

Een ERP systeem dat orders synchroniseert heeft geen gebruikerscontext nodig. Client Credentials flow is hiervoor gemaakt.

php
// Een API client aanmaken (in Laravel Passport admin of via code)
$client = Passport::client()->create([
    'user_id'                => null,
    'name'                   => 'Exact Online Koppeling',
    'secret'                 => Str::random(40),
    'redirect'               => '',
    'personal_access_client' => false,
    'password_client'        => false,
    'revoked'                => false,
]);

Het ERP systeem vraagt een access token aan:

bash
POST /oauth/token
{
    "grant_type": "client_credentials",
    "client_id": "3",
    "client_secret": "jouw-client-secret",
    "scope": "orders:read inventory:write"
}

Response:

json
{
    "token_type": "Bearer",
    "expires_in": 31536000,
    "access_token": "eyJ0eXAiOiJKV1Qi..."
}
php
// Routes beveiligen voor machine-to-machine clients
Route::middleware(['auth:api', 'scope:orders:read'])->group(function () {
    Route::get('/orders', [OrderController::class, 'index']);
});

Authorization Code voor externe koppelingen

Stel dat een marketplace platform namens jouw klanten orders wil plaatsen. De klant moet expliciet toestemming geven. Authorization Code flow regelt dit.

php
// Passport routes zijn automatisch geregistreerd via Passport::routes()
// Jouw klant wordt doorgestuurd naar:
// GET /oauth/authorize?client_id=5&response_type=code&scope=orders:create&redirect_uri=...

// Na goedkeuring ontvangt de marketplace een authorization code
// Die ruilen ze in voor een access token:
// POST /oauth/token
// { "grant_type": "authorization_code", "code": "...", "redirect_uri": "...", "client_id": "5", "client_secret": "..." }

Dit patroon herken je van "Login met Google" of "Koppel je webshop aan Bol.com". Passport maakt het mogelijk om dit zelf aan te bieden aan partners.

De beslismatrix

SituatieKeuzeReden
React/Vue SPA zelfde domeinSanctum (cookies)Eenvoudiger, veiliger dan tokens in localStorage
Mobiele app (iOS/Android)Sanctum (tokens)Simpel token management, scopes voor rechten
ERP/WMS koppeling server-to-serverSanctum (tokens) of Passport (Client Credentials)Sanctum als je geen OAuth nodig hebt
Externe partijen koppelen (OAuth2)PassportAuthorization Code flow vereist Passport
Marketplace integratiesPassportThird-party toegang met gebruikerstoestemming
Microservices internSanctum of Passport CCAfhankelijk van complexiteit

De vuistregel: begin met Sanctum. Schakel over naar Passport alleen als je een OAuth 2.0 flow nodig hebt die Sanctum niet ondersteunt.

Token levensduur en rotatie

Ongeacht welk pakket je kiest, stel token levensduur in.

php
// config/sanctum.php — Sanctum token expiratie
'expiration' => 60 * 24 * 30, // 30 dagen in minuten

// Na expiratie moet de client opnieuw inloggen
// Gebruik refresh tokens voor langere sessies zonder opnieuw inloggen
php
// config/passport.php — Passport token levensduur
use Carbon\CarbonInterval;

'tokens_expire_in' => CarbonInterval::days(15),
'refresh_tokens_expire_in' => CarbonInterval::days(30),
'personal_access_tokens_expire_in' => CarbonInterval::months(6),

Token rotatie bij mobiele apps

Bij mobiele apps roteert een refresh token na gebruik. Zo detecteer je gestolen tokens.

php
// app/Http/Controllers/Api/AuthController.php
public function refresh(Request $request): JsonResponse
{
    $user = $request->user();

    // Verwijder huidig token
    $request->user()->currentAccessToken()->delete();

    // Maak nieuw token aan
    $newToken = $user->createToken('mobile-app', $this->getTokenAbilities($user));

    return response()->json([
        'token' => $newToken->plainTextToken,
    ]);
}

Veiligheid: wat je nooit mag vergeten

  1. Sla tokens nooit op in localStorage — Bij XSS aanvallen leest een aanvaller alles uit localStorage. Gebruik cookies (httpOnly, Secure, SameSite) voor SPA's.
  2. Beperk scopes — Geef tokens minimale rechten. Een readonly koppeling heeft geen write scope nodig.
  3. Revoke tokens bij uitloggen$user->tokens()->delete() voor alle tokens, of $user->currentAccessToken()->delete() voor het huidige token.
  4. Rotate secrets regelmatig — Passport client secrets en Sanctum app keys moeten periodiek roteert worden.
php
// Correcte logout: altijd het token intrekken
public function logout(Request $request): JsonResponse
{
    $request->user()->currentAccessToken()->delete();

    return response()->json(['message' => 'Uitgelogd.']);
}

Conclusie

Sanctum is de juiste keuze voor veruit de meeste e-commerce projecten. SPA's op hetzelfde domein, mobiele apps, interne koppelingen — Sanctum handelt dit af met minimale configuratie.

Passport voeg je toe zodra je externe partijen toegang wilt geven via OAuth 2.0. Marketplace koppelingen, partnerplatforms, multi-tenant autorisatie — dat is het domein van Passport.

Sanctum is onderdeel van het Laravel-ecosysteem — zie de Laravel Sanctum documentatie. Voor OAuth 2.0, zie de Laravel Passport documentatie en de OAuth 2.0 specificatie.

Gerelateerde artikelen:

Bekijk onze Laravel-diensten of neem contact op voor een technisch adviesgesprek.

Ruthger Idema

Geschreven door Ruthger Idema

15+ jaar ervaring in e-commerce development. Gespecialiseerd in Magento, Shopify en Laravel maatwerk.

Meer over ons team →
Deel dit artikel:

Wil je jouw e-commerce naar het volgende niveau?

Plan een vrijblijvend gesprek met onze experts over Magento, Shopify of Laravel maatwerk.

Plan een Tech Check