Laravel Sanctum est la façon la plus simple d'ajouter une authentification à une API moderne. Sans la complexité des bibliothèques JWT ni la lourdeur de configuration d'OAuth, il répond à deux besoins dans un seul paquet : des jetons d'API pour les applications mobiles et les clients tiers, et des sessions basées sur les cookies pour les SPA comme React ou Vue tournant sur le même domaine. Dans cet article, nous mettons en place les deux approches avec du code réel et fonctionnel.
Quand et pourquoi Sanctum ?
L'écosystème Laravel propose trois grandes options d'authentification : Passport pour les projets nécessitant un serveur OAuth2 complet, des bibliothèques externes pour les JWT sans état, et Sanctum, la solution légère dont la plupart des applications ont réellement besoin. Sanctum est le bon choix si vous êtes dans l'une de ces situations :
- Vous avez une application mobile ou un outil en ligne de commande et souhaitez attacher un simple jeton
Bearerà chaque requête. - Votre frontend (SPA) tourne sur le même domaine racine que votre API Laravel et vous n'avez pas besoin d'un véritable flux OAuth.
- Vous voulez accorder des permissions basées sur des capacités (abilities) aux jetons — par exemple, un jeton qui ne peut faire que de la lecture.
Si vous construisez une plateforme ouverte à des développeurs externes qui nécessite des flux OAuth2 (authorization code, client credentials), Passport est plus adapté. Pour la plupart des scénarios concrets, Sanctum est toutefois plus rapide à configurer et demande moins de maintenance.
Installation
Dans Laravel 11 et 12, Sanctum s'installe via la commande install:api en une seule étape. Cette commande publie le paquet, ajoute la migration et prépare le fichier de routes de l'API :
php artisan install:api
Une fois la commande exécutée, les migrations sont déjà lancées et la table personal_access_tokens est créée. Il vous suffit d'ajouter le trait HasApiTokens à votre modèle utilisateur :
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
}
Ce trait dote le modèle de la méthode createToken() et de la relation tokens(). Nous pouvons désormais émettre des jetons.
Émettre et utiliser des jetons d'API
Le scénario le plus courant : un utilisateur se connecte avec son e-mail et son mot de passe, et vous lui renvoyez un jeton. Le client le stocke et l'envoie lors des requêtes suivantes via l'en-tête Authorization: Bearer <token>. Un contrôleur de connexion simple ressemble à ceci :
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' => ['Les identifiants fournis sont incorrects.'],
]);
}
$token = $user->createToken('app-mobile')->plainTextToken;
return response()->json(['token' => $token]);
}
Un détail important ici : plainTextToken renvoie la valeur en clair du jeton uniquement au moment de sa création. La base de données ne stocke qu'un hachage du jeton, donc si vous perdez cette valeur vous ne pourrez pas la récupérer — le client doit l'enregistrer immédiatement.
Protégez vos routes avec le middleware auth:sanctum. Dans routes/api.php :
use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Côté client, la requête ressemble à ceci :
curl https://api.exemple.com/api/user \
-H "Authorization: Bearer 1|abcDEF..." \
-H "Accept: application/json"
Capacités des jetons (abilities)
Sanctum vous permet d'assigner des capacités spécifiques à chaque jeton. C'est une manière propre de limiter ce qu'un jeton peut faire :
$token = $user->createToken('bot-rapport', ['post:read'])->plainTextToken;
Dans un contrôleur ou une route, vous pouvez vérifier cette capacité :
if ($request->user()->tokenCan('post:read')) {
// a la permission de lecture
}
Vous pouvez aussi ajouter les middlewares abilities et ability aux routes pour restreindre l'accès au niveau de la porte d'entrée. Gardez à l'esprit que les capacités ne sont qu'une couche de confort ; vous devez toujours appliquer la véritable logique d'autorisation dans votre application.
Authentification SPA
Pour une SPA tournant sur le même domaine racine, Sanctum utilise les cookies de session de Laravel plutôt que des jetons. Cette approche est plus sûre car vous n'avez pas besoin de garder le jeton dans le localStorage, accessible au JavaScript ; le navigateur gère automatiquement le cookie HttpOnly. Le flux est le suivant :
- La SPA demande d'abord un cookie CSRF au point de terminaison
/sanctum/csrf-cookie. - Elle envoie ensuite une requête web normale à la route
/login; en cas de succès, un cookie de session est défini. - Toutes les requêtes API suivantes arrivent déjà authentifiées grâce à ce cookie.
Trois réglages comptent pour que cela fonctionne. D'abord, mettez supports_credentials à true dans config/cors.php. Ensuite, déclarez le domaine de votre SPA dans le fichier .env :
SANCTUM_STATEFUL_DOMAINS=localhost:3000
SESSION_DOMAIN=localhost
Enfin, le client doit envoyer les cookies avec ses requêtes. Si vous utilisez Axios :
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');
L'erreur la plus fréquente ici est de faire tourner la SPA et l'API sur des domaines totalement différents, puis de se demander pourquoi la session ne tient pas. La méthode basée sur les cookies exige que les deux partagent le même domaine racine (par exemple app.exemple.com et api.exemple.com).
Révoquer les jetons et sécurité
Lorsqu'un utilisateur se déconnecte ou perd un appareil, vous devez invalider les jetons. Pour supprimer le jeton actuel :
$request->user()->currentAccessToken()->delete();
Pour révoquer tous les jetons (déconnexion partout) :
$request->user()->tokens()->delete();
Quelques notes de sécurité : définissez une expiration des jetons via config/sanctum.php (la clé expiration), faites toujours tourner votre API derrière HTTPS, et ajoutez le middleware throttle à votre point de connexion pour limiter les tentatives par force brute. Côté SPA, avoir la protection CSRF active est le plus grand avantage qu'apporte la méthode basée sur les cookies.
Questions fréquentes
Dois-je utiliser Sanctum ou Passport ?
À moins de construire un serveur OAuth2 complet ouvert à des développeurs externes, choisissez Sanctum. Pour les jetons d'application mobile et les sessions SPA internes, Sanctum est à la fois plus léger et plus facile à maintenir. Passport a du sens lorsque vous avez besoin de flux OAuth comme l'authorization code grant.
Où dois-je stocker les jetons ?
Dans les applications mobiles, gardez le jeton dans le stockage sécurisé de la plateforme (iOS Keychain, Android Keystore). Dans les SPA, utilisez l'authentification SPA basée sur les cookies plutôt que la méthode par jeton, afin de ne pas avoir à garder le jeton dans le localStorage accessible au JavaScript.
Pourquoi ma connexion SPA renvoie-t-elle une erreur 419 ?
Une erreur 419 correspond généralement à une non-concordance du jeton CSRF. Assurez-vous d'appeler /sanctum/csrf-cookie avant vos requêtes, que le client envoie bien les cookies (withCredentials), et que SANCTUM_STATEFUL_DOMAINS et SESSION_DOMAIN sont correctement configurés.
Vous souhaitez mettre en place une couche d'authentification sécurisée pour votre API ? Si vous avez besoin d'aide pour l'intégration de Laravel Sanctum, les sessions SPA ou vos API mobiles, contactez-moi — construisons ensemble la solution la mieux adaptée à votre projet.