Passer au contenu principal

Qu’est-ce que Sanctum

Laravel Sanctum est un package d’authentification léger destiné aux SPA, applications mobiles et APIs simples. Sans connaître OAuth, vous pouvez émettre et gérer plusieurs tokens API par utilisateur. Deux problèmes résolus :
ModeMécanismeUsage principal
Tokens APIEn-tête Authorization: Bearer <token>Mobile, intégrations tierces
SPACookie de session + CSRFFrontend maison (Vue, React…)
Utilisez le mode SPA pour vos SPA maison, et les tokens API pour mobile ou clients tiers. Vous pouvez utiliser un seul mode.

Sanctum vs Passport

SanctumPassport
ComplexitéSimpleOAuth2 complet
UsageSPA/mobile maisonServeur OAuth2 pour applications externes
Type de tokenPersonal access tokenOAuth2 access token
Choisissez Passport si vous devez être un fournisseur OAuth2. Sinon, Sanctum suffit à la plupart des applications.

Installation et configuration

Installation

install:api configure Sanctum.
php artisan install:api
Cette commande :
  • installe laravel/sanctum
  • publie la migration personal_access_tokens
  • exécute la migration

Ajouter le trait HasApiTokens

Ajoutez le trait au modèle User.
// app/Models/User.php

use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}
Vous disposez alors de $user->createToken(), $user->tokens, etc.

Authentification par token API

Flux

Émission d’un token

createToken() génère un token. plainTextToken contient la version en clair. Elle n’est pas persistée : renvoyez-la immédiatement à l’utilisateur.
use Illuminate\Http\Request;

Route::post('/tokens/create', function (Request $request) {
    $token = $request->user()->createToken($request->token_name);

    return ['token' => $token->plainTextToken];
})->middleware('auth');
Le hash SHA-256 seul est stocké en base.

Portées (abilities)

Restreignez les actions autorisées par le token via des abilities.
$token = $user->createToken('mobile-app', ['server:update', 'server:read']);

return $token->plainTextToken;
Vérifiez à l’exécution :
if ($request->user()->tokenCan('server:update')) {
    // Mise à jour
}

if ($request->user()->tokenCant('server:update')) {
    abort(403);
}

Vérifier via middleware

Alias dans bootstrap/app.php :
use Laravel\Sanctum\Http\Middleware\CheckAbilities;
use Laravel\Sanctum\Http\Middleware\CheckForAnyAbility;

->withMiddleware(function (Middleware $middleware): void {
    $middleware->alias([
        'abilities' => CheckAbilities::class,  // Toutes
        'ability'   => CheckForAnyAbility::class, // Au moins une
    ]);
})
Application aux routes :
// Doit avoir check-status ET place-orders
Route::get('/orders', function () {
    // ...
})->middleware(['auth:sanctum', 'abilities:check-status,place-orders']);

// Doit avoir au moins une des deux
Route::get('/orders', function () {
    // ...
})->middleware(['auth:sanctum', 'ability:check-status,place-orders']);

Expiration

Par défaut, pas d’expiration. Réglez expiration (minutes) dans config/sanctum.php.
// config/sanctum.php
'expiration' => 525600, // 365 jours (en minutes)
Expiration par token :
$token = $user->createToken(
    'token-name',
    ['*'],
    now()->addWeeks(1)
)->plainTextToken;
Programme la purge :
use Illuminate\Support\Facades\Schedule;

Schedule::command('sanctum:prune-expired --hours=24')->daily();

Révocation

// Tous les tokens
$user->tokens()->delete();

// Token courant
$request->user()->currentAccessToken()->delete();

// Token précis
$user->tokens()->where('id', $tokenId)->delete();

Authentification SPA

Basée sur les cookies de session — pas de gestion de token. Idéal pour votre frontend Vue/React/Next.js maison.
SPA et API doivent partager le même TLD (sous-domaines différents autorisés). Envoyez Accept: application/json et un Referer ou Origin.

Activer le middleware

Dans bootstrap/app.php :
->withMiddleware(function (Middleware $middleware): void {
    $middleware->statefulApi();
})

Domaines first-party

Dans config/sanctum.php, réglez stateful.
// 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()
))),

CORS

Pour un autre sous-domaine :
php artisan config:publish cors
Dans config/cors.php :
'supports_credentials' => true,
Côté frontend (axios) :
// resources/js/bootstrap.js
axios.defaults.withCredentials = true;
axios.defaults.withXSRFToken = true;
N’oubliez pas le domaine de session :
// config/session.php
'domain' => '.example.com', // avec le point

Flux d’authentification

1

Récupérer le cookie CSRF

Avant de se connecter, initialisez CSRF.
await axios.get('/sanctum/csrf-cookie');
2

Envoyer la requête de login

await axios.post('/login', {
    email: '[email protected]',
    password: 'password',
});
3

Requêtes authentifiées

Les requêtes suivantes utilisent le cookie de session.
const response = await axios.get('/api/user');
console.log(response.data);

Protéger les routes

auth:sanctum retourne 401 Unauthorized pour les requêtes non authentifiées. Ce middleware unique gère à la fois tokens API et SPA.
use Illuminate\Http\Request;

// Route seule
Route::get('/user', function (Request $request) {
    return $request->user();
})->middleware('auth:sanctum');

// Groupe de routes
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/profile', [ProfileController::class, 'show']);
    Route::put('/profile', [ProfileController::class, 'update']);
    Route::get('/posts', [PostController::class, 'index']);
});

Exemple : login API et renvoi d’un token

Cas mobile.
1

Endpoint de login

// routes/api.php

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\ValidationException;

Route::post('/sanctum/token', function (Request $request) {
    $request->validate([
        'email'       => ['required', 'email'],
        'password'    => ['required'],
        'device_name' => ['required', 'string'],
    ]);

    $user = User::where('email', $request->email)->first();

    if (! $user || ! Hash::check($request->password, $user->password)) {
        throw ValidationException::withMessages([
            'email' => ['Les identifiants fournis sont incorrects.'],
        ]);
    }

    return response()->json([
        'token' => $user->createToken($request->device_name)->plainTextToken,
    ]);
});
2

Routes authentifiées

// routes/api.php

Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', function (Request $request) {
        return $request->user();
    });

    Route::post('/logout', function (Request $request) {
        $request->user()->currentAccessToken()->delete();

        return response()->json(['message' => 'Déconnecté.']);
    });

    Route::post('/logout/all', function (Request $request) {
        $request->user()->tokens()->delete();

        return response()->json(['message' => 'Déconnexion de tous les appareils.']);
    });
});
3

Requêtes client

// Login
const { data } = await axios.post('/api/sanctum/token', {
    email: '[email protected]',
    password: 'password',
    device_name: 'My iPhone',
});

const token = data.token;

// Requêtes authentifiées
const response = await axios.get('/api/user', {
    headers: {
        Authorization: `Bearer ${token}`,
    },
});

Tests

Utilisez Sanctum::actingAs() pour authentifier avec des abilities.
use App\Models\User;
use Laravel\Sanctum\Sanctum;

test('récupère la liste des tâches', function () {
    Sanctum::actingAs(
        User::factory()->create(),
        ['view-tasks']
    );

    $response = $this->get('/api/tasks');

    $response->assertOk();
});

test('accède avec toutes les abilities', function () {
    Sanctum::actingAs(
        User::factory()->create(),
        ['*']
    );

    $response = $this->get('/api/tasks');

    $response->assertOk();
});

Récapitulatif

php artisan install:api
Ajout du trait HasApiTokens :
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;
}
// Émission
$token = $user->createToken('token-name')->plainTextToken;

// Avec abilities
$token = $user->createToken('token-name', ['read', 'write'])->plainTextToken;

// Vérification
$user->tokenCan('read');
$user->tokenCant('write');

// Révocation
$user->tokens()->delete();
$request->user()->currentAccessToken()->delete();
$user->tokens()->where('id', $id)->delete();
  • Tokens API : mobile, intégrations tierces, CLI — clients sans session.
  • SPA : Vue/React/Next.js maison sur le même domaine — plus sûr, sans gestion de token.
Dernière modification le 13 juillet 2026