Intégration Auth0 Laravel API
Protégez les endpoints de l'API Laravel avec la validation JWT des access tokens en utilisant auth0/login et AuthorizationGuard.
Prérequis
- Application Laravel 11+
- PHP 8.2+ avec extensions :
mbstring,openssl,json - Composer installé
- Ressource API Auth0 configurée (pas une Application - doit être une API)
- Si vous n'avez pas encore Auth0 configuré, utilisez d'abord la skill
auth0-quickstart
Quand NE PAS utiliser
| Scénario | À utiliser à la place |
|---|---|
| Application web Laravel avec UI de login/logout | auth0-laravel (session-based AuthenticationGuard) |
| API PHP brute (sans framework) | auth0-php-api |
| Application web PHP brute | auth0-php |
| Single Page Applications | auth0-react, auth0-vue, ou auth0-angular |
| APIs FastAPI / Python | auth0-fastapi-api |
| APIs Express / Node.js | express-oauth2-jwt-bearer |
| Émission de tokens | Cette skill est pour valider les access tokens, pas les émettre |
Flux de démarrage rapide
1. Installer le SDK
composer require auth0/login
Le package auth0/login nécessite auth0/auth0-php (v8.19+) et l'installe automatiquement. Il nécessite aussi un client HTTP PSR-18 - si vous n'en avez pas déjà un :
composer require guzzlehttp/guzzle guzzlehttp/psr7
2. Publier la configuration
php artisan vendor:publish --tag=auth0
Ceci crée config/auth0.php avec la configuration de guard, middleware et routes.
3. Créer une API Auth0
Vous avez besoin d'une API (pas une Application) dans Auth0.
STOP - demandez à l'utilisateur avant de continuer.
Posez exactement cette question et attendez sa réponse avant de faire autre chose :
« Comment souhaitez-vous créer la ressource API Auth0 ?
- Automatisé - Je vais exécuter des scripts Auth0 CLI qui créent la ressource et écrivez les valeurs exactes dans votre
.envautomatiquement.- Manuel - Vous créez l'API vous-même dans le Auth0 Dashboard (ou via
auth0 apis create) et me fournissez le Domain et l'Audience.Que préférez-vous ? (1 = Automatisé / 2 = Manuel) »
Ne procédez à AUCUNE étape de configuration tant que l'utilisateur n'a pas répondu. Ne faites pas défaut à la méthode manuelle.
Si l'utilisateur a choisi Automatisé, suivez le Guide de configuration pour les scripts CLI complets. Le chemin automatisé écrit .env pour vous - ignorez l'étape 4 ci-dessous et passez directement à l'étape 5.
Si l'utilisateur a choisi Manuel, suivez le Guide de configuration (section Configuration manuelle) pour les instructions complètes. Puis continuez avec l'étape 4 ci-dessous.
Référence rapide pour la création manuelle d'API :
auth0 apis create \
--name "My Laravel API" \
--identifier https://my-api.example.com \
--json
Ou créez manuellement dans Auth0 Dashboard -> Applications -> APIs
4. Configurer l'environnement
Ajoutez à votre .env :
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_AUDIENCE=https://your-api.example.com
AUTH0_DOMAIN est le domaine de votre tenant Auth0 (sans https://). AUTH0_AUDIENCE est l'identifiant API que vous avez défini lors de la création de la ressource API dans Auth0.
5. Configurer Auth Guard
Mettez à jour config/auth.php pour ajouter le guard API :
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'auth0-api' => [
'driver' => 'auth0.authorizer',
'provider' => 'auth0-provider',
'configuration' => 'api',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'auth0-provider' => [
'driver' => 'auth0.provider',
'repository' => 'auth0.repository',
],
],
Points clés :
driverdoit êtreauth0.authorizer(pasauth0.authenticatorqui est pour les applications web)configurationdoit être'api'qui mappe vers le guardapidansconfig/auth0.php- Le SDK enregistre automatiquement un guard
auth0-apiavec cette config, mais le définir explicitement est plus clair
6. Vérifier la configuration Auth0
Après la publication, vérifiez que config/auth0.php contient une clé guards.api avec strategy défini à SdkConfiguration::STRATEGY_API (valeur : 'api'). Ceci est déjà présent dans la config publiée — aucune édition manuelle n'est nécessaire.
Le fichier publié utilise des constantes de classe pour les clés (par ex. Configuration::CONFIG_STRATEGY), qui se résolvent aux mêmes valeurs de chaîne au runtime :
'guards' => [
'api' => [
'strategy' => SdkConfiguration::STRATEGY_API, // valeur : 'api'
],
],
La config publiée inclut aussi les sections de guard default et web — elles peuvent être ignorées pour une utilisation API uniquement. La stratégie STRATEGY_API désactive toute la machinerie session/cookie et active la validation Bearer token sans état.
7. Ajouter des routes API protégées
Laravel 11+ n'inclut pas routes/api.php par défaut. Si le fichier n'existe pas, générez-le :
php artisan install:api
Ceci crée routes/api.php et l'enregistre dans bootstrap/app.php avec le préfixe /api. Cela installe aussi Laravel Sanctum, qui n'est pas utilisé mais inoffensif à côté d'Auth0.
Dans routes/api.php :
use Illuminate\Support\Facades\Route;
Route::get('/public', function () {
return response()->json(['message' => 'Public endpoint - no authentication required']);
});
Route::middleware('auth:auth0-api')->group(function () {
Route::get('/private', function () {
$user = auth('auth0-api')->user();
return response()->json([
'message' => 'Private endpoint',
'sub' => $user->getAuthIdentifier(),
]);
});
});
Le middleware auth:auth0-api valide le token Bearer, vérifie la signature contre l'endpoint JWKS, et contrôle les claims issuer et audience. Les requêtes sans token valide reçoivent une réponse 401.
8. Vérifications de scope et permission
Utilisez les méthodes hasScope() et hasPermission() du guard :
Route::middleware('auth:auth0-api')->group(function () {
Route::get('/messages', function () {
$guard = auth('auth0-api');
if (!$guard->hasScope('read:messages')) {
return response()->json(['error' => 'insufficient_scope'], 403);
}
return response()->json(['messages' => []]);
});
Route::delete('/users/{id}', function (string $id) {
$guard = auth('auth0-api');
if (!$guard->hasPermission('delete:users')) {
return response()->json(['error' => 'insufficient_permissions'], 403);
}
return response()->json(['deleted' => $id]);
});
});
hasScope()vérifie le claimscope(chaîne séparée par des espaces dans le JWT)hasPermission()vérifie le claimpermissions(array, nécessite RBAC activé sur l'API dans Auth0 Dashboard)
9. Claims d'access token
L'utilisateur authentifié est une instance StatelessUser avec accès dynamique aux claims :
Route::middleware('auth:auth0-api')->get('/profile', function () {
$user = auth('auth0-api')->user();
return response()->json([
'sub' => $user->getAuthIdentifier(),
'email' => $user->email,
'permissions' => $user->permissions ?? [],
'all_claims' => $user->jsonSerialize(),
]);
});
Les claims sont accessibles via :
$user->getAuthIdentifier()- Retourne le claimsub$user->claim_name- Accès via propriété dynamique via__get$user->getAttribute('claim_name')- Accès explicite$user->jsonSerialize()- Tous les claims comme array
10. Tester l'API
Instruction agent : Démarrez le serveur dev Laravel et vérifiez que les endpoints de base fonctionnent sans credentials :
php artisan serve & sleep 2 curl -s -H "Accept: application/json" http://localhost:8000/api/public curl -s -o /dev/null -w "%{http_code}" -H "Accept: application/json" http://localhost:8000/api/private
/api/publicdoit retourner{"message":"Public endpoint - no authentication required"}/api/privatedoit retourner HTTP 401Important : L'en-tête
-H "Accept: application/json"est requis. Sans lui, le middlewareAuthenticatede Laravel retourne une redirection 302 au lieu de 401.Si les deux passent, le guard fonctionne. Tuez le serveur en arrière-plan quand c'est fait :
kill %1 2>/dev/nullVérification d'échec : Si le serveur ne démarre pas ou que les réponses sont inattendues, vérifiez que
config/auth0.phpexiste et que.envaAUTH0_DOMAINetAUTH0_AUDIENCEdéfinis. Après 5-6 itérations échouées, utilisezAskUserQuestion.
Instruction agent : STOP - demandez après que les tests de base passent.
Une fois que les tests public/401 passent, demandez à l'utilisateur :
« Votre API est configurée et le guard fonctionne (public retourne 200, private retourne 401 sans token). Souhaitez-vous que je vous aide à configurer les tests avec un vrai access token ?
- Oui - Je vais vous aider à configurer une application M2M pour obtenir des tokens de test.
- Non - Je suis terminé pour maintenant.
Que préférez-vous ? »
Ne procédez avec la configuration M2M/token que si l'utilisateur dit oui.
Instruction agent (configuration app M2M - seulement si l'utilisateur veut les tests) :
Si l'utilisateur a choisi de configurer les tests, demandez :
« Pour tester vos endpoints protégés, vous avez besoin d'une application Machine-to-Machine (M2M) autorisée à demander des tokens pour cette API.
- Créer une nouvelle - Je vais créer une nouvelle application M2M et l'autoriser pour cette API.
- Utiliser une existante - Vous avez déjà une application M2M. Fournissez le Client ID et je vais l'autoriser pour cette API.
Que préférez-vous ? (1 = Créer une nouvelle / 2 = Utiliser une existante) »
Ne procédez pas avant que l'utilisateur réponde.
Si l'utilisateur a choisi « Créer une nouvelle » :
auth0 apps create \ --name "${PWD##*/} (Test App)" \ --type m2m \ --no-input --jsonAnalysez JSON avec
jqpour extraireclient_id. N'utilisez PAS--reveal-secrets. Puis créez une client grant :auth0 api post "client-grants" --data '{ "client_id": "<CLIENT_ID>", "audience": "<API_IDENTIFIER>", "scope": ["<SCOPES>"] }'Si l'utilisateur a choisi « Utiliser une existante » : Demandez le Client ID. Créez une client grant (conflit 409 = déjà autorisé, c'est bon).
Instruction agent (ISOLATION DU TOKEN - CRITIQUE) :
L'agent NE DOIT JAMAIS voir directement ou afficher les valeurs d'access token.
- Ne lancez PAS
auth0 test tokenseul- Ne demandez PAS à l'utilisateur de coller son token
- N'affichez ou ne stockez PAS la valeur du token
Tests sécurisés (chaîne de commande unique) :
php artisan serve & sleep 2 TEST_TOKEN=$(auth0 test token <M2M_CLIENT_ID> --audience <AUDIENCE> --scopes <SCOPE1,SCOPE2> 2>/dev/null | grep -o 'ey[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*') && \ [ -n "$TEST_TOKEN" ] && echo "Token acquired (${#TEST_TOKEN} chars)" && \ curl -s -H "Accept: application/json" -H "Authorization: Bearer $TEST_TOKEN" http://localhost:8000/api/private kill %1 2>/dev/nullSi l'utilisateur NE demande PAS de test, fournissez les commandes à exécuter manuellement :
auth0 test token <CLIENT_ID> --audience <AUDIENCE> --scopes <SCOPE1,SCOPE2> curl -H "Accept: application/json" -H "Authorization: Bearer <PASTE_TOKEN_HERE>" http://localhost:8000/api/private
Démarrez le serveur :
php artisan serve
Testez l'endpoint public (aucun token requis) :
curl -H "Accept: application/json" http://localhost:8000/api/public
Testez l'endpoint protégé sans token (doit retourner 401) :
curl -H "Accept: application/json" http://localhost:8000/api/private
Note : L'en-tête Accept: application/json est requis. Sans lui, Laravel redirige (302) au lieu de retourner 401.
Testez l'endpoint protégé avec token :
curl http://localhost:8000/api/private \
-H "Accept: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Obtenez un token de test via Auth0 Dashboard -> APIs -> onglet Test, ou via le flux M2M décrit ci-dessus.
Erreurs courantes
| Erreur | Correction |
|---|---|
Utiliser le driver auth0.authenticator pour les routes API |
Le guard API doit utiliser auth0.authorizer - auth0.authenticator est pour les applications web avec session |
Utiliser le middleware auth:web pour les routes API |
Utilisez auth:auth0-api pour spécifier le guard API |
| Créé une Application au lieu d'une API dans Auth0 | Doit créer une ressource API (Dashboard -> Applications -> APIs) |
Passing domain avec le préfixe https:// |
Utilisez le domaine nu : tenant.us.auth0.com pas https://tenant.us.auth0.com |
Utiliser auth0/auth0-php directement |
Utilisez auth0/login qui encapsule le SDK avec les guards et middleware Laravel |
| Ne pas publier la config | Lancez php artisan vendor:publish --tag=auth0 avant de configurer |
AUTH0_AUDIENCE manquant dans .env |
Requis pour la validation du token - sans lui, les tokens ne peuvent pas être vérifiés contre la bonne audience |
Utiliser $request->user() sans nom de guard |
Par défaut le guard web - utilisez auth('auth0-api')->user() ou $request->user('auth0-api') |
Vérifier $user->scope comme chaîne |
Le claim scope dans les JWTs est séparé par des espaces - utilisez hasScope() au lieu de comparaison de chaîne |
Appeler hasPermission() sans activer RBAC |
Doit activer "Add Permissions in the Access Token" dans Auth0 Dashboard -> APIs -> Settings |
| Utiliser les tokens ID pour l'authentification API | Doit utiliser les access tokens - les tokens ID sont pour l'application client |
Configurer configuration => 'web' sur le guard API |
Doit être 'api' qui mappe à la config STRATEGY_API dans config/auth0.php |
Tester avec curl sans l'en-tête Accept: application/json |
Laravel retourne une redirection 302 au lieu de 401 - envoyez toujours Accept: application/json pour les requêtes API |
hasScope() retourne false pour les scopes non définis sur l'API |
Les scopes doivent être définis sur la ressource API dans Auth0 Dashboard - demander un scope dans la requête de token ne l'accorde pas sauf s'il est défini |
hasPermission() retourne false avec les tokens M2M |
Les permissions RBAC ne sont embarquées que dans les tokens des flux basés utilisateur (Authorization Code), pas dans les grants client-credentials |
routes/api.php manquant dans Laravel 11+ |
Lancez php artisan install:api pour générer le routage API - Laravel 11 ne l'inclut pas par défaut |
Méthodes principales du SDK
| Méthode | Retourne | Objectif |
|---|---|---|
auth('auth0-api')->user() |
?StatelessUser |
Retourne l'utilisateur authentifié ou null |
auth('auth0-api')->check() |
bool |
Si la requête a un token valide |
auth('auth0-api')->hasScope($scope) |
bool |
Vérifier si le token a un scope spécifique |
auth('auth0-api')->hasPermission($perm) |
bool |
Vérifier si le token a une permission RBAC spécifique |
auth('auth0-api')->id() |
?string |
Retourne le claim sub directement |
$user->getAuthIdentifier() |
int\|string\|null |
Retourne le claim sub |
$user->getAttribute('key') |
mixed |
Retourne la valeur de n'importe quel claim |
$user->jsonSerialize() |
array |
Retourne tous les claims comme array |
auth('auth0-api')->getCredential() |
?CredentialEntity |
Identifiant complet avec données de token décodées |
Skills connexes
auth0-laravel- Pour les applications web Laravel avec login/logout utilisant l'authentification par sessionauth0-php-api- Pour les APIs PHP brutes sans Laravelauth0-quickstart- Configuration initiale Auth0auth0-mfa- Ajouter l'authentification multifacteurauth0-cli- Gérer les ressources Auth0 depuis le terminal
Référence rapide
Configuration du guard (config/auth.php) :
'guards' => [
'auth0-api' => [
'driver' => 'auth0.authorizer',
'provider' => 'auth0-provider',
'configuration' => 'api',
],
],
'providers' => [
'auth0-provider' => [
'driver' => 'auth0.provider',
'repository' => 'auth0.repository',
],
],
Protection des routes :
Route::middleware('auth:auth0-api')->group(function () {
Route::get('/resource', fn() => response()->json([...]));
});
Vérifications de scope/permission :
$guard = auth('auth0-api');
$guard->hasScope('read:messages'); // vérifie le claim scope
$guard->hasPermission('delete:users'); // vérifie le claim permissions (RBAC)
Claims utilisateur :
$user = auth('auth0-api')->user();
$user->getAuthIdentifier(); // sub
$user->email; // n'importe quel claim via __get
$user->getAttribute('iss'); // accès explicite au claim
Variables d'environnement :
AUTH0_DOMAIN- Domaine du tenant Auth0 (ex.tenant.us.auth0.com)AUTH0_AUDIENCE- Identifiant API (ex.https://api.example.com)
Cas d'usage courants :
- Protéger les routes -> middleware
auth:auth0-api(voir étape 7) - Enforcement de scope ->
hasScope()(voir étape 8) - Enforcement de permission ->
hasPermission()(voir étape 8) - Configuration avancée -> Référence API
Documentation détaillée
- Guide de configuration - Configuration Auth0 CLI, configuration environnement, obtention des tokens de test
- Guide d'intégration - Scopes, permissions, CORS, repositories utilisateur personnalisés, gestion d'erreurs, multi-guard
- Référence API - API complète AuthorizationGuard, StatelessUser, CredentialEntity, options de configuration