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 :
Mode Mécanisme Usage principal Tokens API En-tête Authorization: Bearer <token> Mobile, intégrations tierces SPA Cookie de session + CSRF Frontend 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
Sanctum Passport Complexité Simple OAuth2 complet Usage SPA/mobile maison Serveur OAuth2 pour applications externes Type de token Personal access token OAuth2 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.
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
Récupérer le cookie CSRF
Avant de se connecter, initialisez CSRF. await axios . get ( '/sanctum/csrf-cookie' );
Envoyer la requête de login
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.
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 ,
]);
});
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.' ]);
});
});
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 ();
});
use App\Models\ User ;
use Laravel\Sanctum\ Sanctum ;
public function test_task_list_can_be_retrieved () : void
{
Sanctum :: actingAs (
User :: factory () -> create (),
[ 'view-tasks' ]
);
$response = $this -> get ( '/api/tasks' );
$response -> assertOk ();
}
Récapitulatif
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.