auth0-laravel-api

Par auth0 · agent-skills

À utiliser pour sécuriser les endpoints d'API Laravel avec validation de token JWT Bearer, vérifications de scope/permission ou auth sans état — intègre auth0/login (laravel-auth0) avec l'`AuthorizationGuard` pour les API REST recevant des access tokens provenant de SPAs, d'applications mobiles ou d'autres clients. Se déclenche sur : Laravel API auth, auth0.authorizer, AuthorizationGuard, Laravel JWT, stateless Bearer.

npx skills add https://github.com/auth0/agent-skills --skill auth0-laravel-api

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 ?

  1. Automatisé - Je vais exécuter des scripts Auth0 CLI qui créent la ressource et écrivez les valeurs exactes dans votre .env automatiquement.
  2. 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 :

  • driver doit être auth0.authorizer (pas auth0.authenticator qui est pour les applications web)
  • configuration doit être 'api' qui mappe vers le guard api dans config/auth0.php
  • Le SDK enregistre automatiquement un guard auth0-api avec 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 claim scope (chaîne séparée par des espaces dans le JWT)
  • hasPermission() vérifie le claim permissions (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 claim sub
  • $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/public doit retourner {"message":"Public endpoint - no authentication required"}
  • /api/private doit retourner HTTP 401

Important : L'en-tête -H "Accept: application/json" est requis. Sans lui, le middleware Authenticate de 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/null

Vérification d'échec : Si le serveur ne démarre pas ou que les réponses sont inattendues, vérifiez que config/auth0.php existe et que .env a AUTH0_DOMAIN et AUTH0_AUDIENCE définis. Après 5-6 itérations échouées, utilisez AskUserQuestion.

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 ?

  1. Oui - Je vais vous aider à configurer une application M2M pour obtenir des tokens de test.
  2. 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.

  1. Créer une nouvelle - Je vais créer une nouvelle application M2M et l'autoriser pour cette API.
  2. 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 --json

Analysez JSON avec jq pour extraire client_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 token seul
  • 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/null

Si 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 session
  • auth0-php-api - Pour les APIs PHP brutes sans Laravel
  • auth0-quickstart - Configuration initiale Auth0
  • auth0-mfa - Ajouter l'authentification multifacteur
  • auth0-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

Références

Skills similaires