Intégration Auth0 PHP API
Protégez les endpoints PHP API avec la validation des tokens d'accès JWT en utilisant auth0/auth0-php en mode API (STRATEGY_API).
Prérequis
- PHP 8.2+ avec les extensions :
mbstring,openssl,json - Composer installé
- Ressource Auth0 API configurée (pas une Application - doit être une API)
- Si vous n'avez pas encore Auth0, utilisez d'abord la skill
auth0-quickstart
Quand NE PAS utiliser
- Applications PHP web avec flux login/logout - Utilisez
auth0-phppour l'authentification basée sur les sessions - Applications Laravel - Utilisez
auth0/laravel-auth0qui inclut le support intégré pour les API - Applications Symfony - Utilisez
auth0/symfonyavec son bundle de sécurité - Applications monopage - Utilisez
auth0-react,auth0-vue, ouauth0-angularpour l'authentification côté client - Émission de tokens - Cette skill sert à valider les tokens d'accès, pas à les émettre
Workflow de démarrage rapide
1. Installer le SDK
composer require auth0/auth0-php vlucas/phpdotenv guzzlehttp/guzzle guzzlehttp/psr7 "symfony/cache:^7.0"
auth0/auth0-php- Le SDK Auth0 (v8.x)vlucas/phpdotenv- Charger les fichiers.envdans$_ENVguzzlehttp/guzzle+guzzlehttp/psr7- Client HTTP PSR-18 requis par le SDKsymfony/cache- Cache PSR-6 pour le cache des clés JWKS (recommandé pour la production)
2. 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 quoi que ce soit d'autre :
"Comment souhaitez-vous créer la ressource Auth0 API ?
- Automatisé - Je vais exécuter les scripts de l'Auth0 CLI qui créent la ressource et écrivent les valeurs exactes dans votre
.envautomatiquement.- Manuel - Vous créez l'API vous-même dans le tableau de bord Auth0 (ou via
auth0 apis create) et me fournissez le Domain et Audience.Laquelle préférez-vous ? (1 = Automatisé / 2 = Manuel)"
Ne procédez à AUCUNE étape de configuration jusqu'à ce que l'utilisateur ait répondu. Ne choisissez PAS par défaut le manuel.
Si l'utilisateur a choisi Automatisé, suivez le Guide de configuration pour les scripts CLI complets. Le chemin automatisé écrit .env pour vous - passez l'étape 3 ci-dessous et procédez directement à l'étape 4.
Si l'utilisateur a choisi Manuel, suivez le Guide de configuration (section Configuration manuelle) pour les instructions complètes. Puis continuez avec l'étape 3 ci-dessous.
Référence rapide pour la création manuelle d'une API :
# Utilisant l'Auth0 CLI
auth0 apis create \
--name "My PHP API" \
--identifier https://my-api.example.com \
--json
Ou créez manuellement dans le tableau de bord Auth0 -> Applications -> APIs
3. Configurer l'environnement
Créez .env :
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_AUDIENCE=https://your-api.example.com
AUTH0_DOMAIN est votre domaine de tenant Auth0 (sans https://). AUTH0_AUDIENCE est l'identifiant de l'API que vous avez défini lors de la création de la ressource API dans Auth0.
4. Initialiser Auth0 en mode API
Créez auth0.php pour initialiser le SDK :
<?php
require 'vendor/autoload.php';
use Auth0\SDK\Auth0;
use Auth0\SDK\Configuration\SdkConfiguration;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
$configuration = new SdkConfiguration(
strategy: SdkConfiguration::STRATEGY_API,
domain: $_ENV['AUTH0_DOMAIN'],
clientId: null,
audience: [$_ENV['AUTH0_AUDIENCE']],
tokenAlgorithm: 'RS256',
tokenCache: new FilesystemAdapter('auth0_jwks', 600, __DIR__ . '/var/cache'),
tokenCacheTtl: 600,
);
$auth0 = new Auth0($configuration);
Différences clés par rapport au mode app web :
STRATEGY_API- sans état, aucune session ni cookieclientIdn'est pas requis pour la validation RS256 (requis seulement pour HS256)audienceaccepte un tableau de chaînes d'audience autoriséestokenCacheest unCacheItemPoolInterfacePSR-6 pour le cache JWKS
5. Créer une fonction middleware
Puisque le SDK n'inclut pas de middleware intégré, créez une fonction de garde réutilisable. Créez middleware.php :
<?php
use Auth0\SDK\Auth0;
use Auth0\SDK\Token;
use Auth0\SDK\Exception\InvalidTokenException;
function requireAuth(Auth0 $auth0, ?array $requiredScopes = null): array
{
$token = $auth0->getBearerToken(
server: ['HTTP_AUTHORIZATION']
);
if ($token === null) {
http_response_code(401);
header('Content-Type: application/json');
echo json_encode(['error' => 'unauthorized', 'message' => 'Missing or invalid Bearer token']);
exit;
}
$claims = $token->toArray();
if ($requiredScopes !== null) {
$grantedScopes = isset($claims['scope']) ? explode(' ', $claims['scope']) : [];
$missingScopes = array_diff($requiredScopes, $grantedScopes);
if (!empty($missingScopes)) {
http_response_code(403);
header('Content-Type: application/json');
echo json_encode(['error' => 'insufficient_scope', 'message' => 'Token lacks required scopes']);
exit;
}
}
return $claims;
}
getBearerToken() cherche un token Bearer aux emplacements que vous spécifiez, vérifie la signature contre l'endpoint JWKS et valide les claims (émetteur, audience, expiration). Le paramètre server est un tableau de noms de clés $_SERVER à vérifier (par ex. ['HTTP_AUTHORIZATION']) - pas $_SERVER lui-même. Retourne un TokenInterface en cas de succès ou null si aucun token valide n'est trouvé (ne lève pas d'exception).
6. Créer les routes API
Créez index.php comme contrôleur frontal :
<?php
require 'auth0.php';
require 'middleware.php';
$method = $_SERVER['REQUEST_METHOD'];
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
header('Content-Type: application/json');
switch ($path) {
case '/api/public':
echo json_encode(['message' => 'Public endpoint - no authentication required']);
break;
case '/api/private':
$claims = requireAuth($auth0);
echo json_encode(['message' => 'Private endpoint', 'sub' => $claims['sub']]);
break;
case '/api/private-scoped':
$claims = requireAuth($auth0, ['read:messages']);
echo json_encode(['messages' => [], 'sub' => $claims['sub']]);
break;
default:
http_response_code(404);
echo json_encode(['error' => 'not_found']);
break;
}
7. Accéder aux claims du token d'accès
Les claims JWT décodés sont retournés sous forme d'un tableau associatif :
$claims = requireAuth($auth0);
$userId = $claims['sub']; // user/client ID
$scopes = $claims['scope']; // scopes accordés séparés par des espaces
$issuer = $claims['iss']; // émetteur (votre URL de domaine Auth0)
$audience = $claims['aud']; // audience (chaîne ou tableau)
$expiration = $claims['exp']; // timestamp d'expiration
Vous pouvez aussi utiliser les méthodes d'accès typées de l'objet Token :
$token = $auth0->getBearerToken(server: ['HTTP_AUTHORIZATION']);
if ($token !== null) {
$subject = $token->getSubject(); // retourne ?string
$issuer = $token->getIssuer(); // retourne ?string
$audience = $token->getAudience(); // retourne ?array
$expiration = $token->getExpiration(); // retourne ?int
}
8. Ajouter les en-têtes CORS
Quand votre API reçoit des requêtes d'une SPA basée sur un navigateur, ajoutez les en-têtes CORS. Créez cors.php :
<?php
function handleCors(array $allowedOrigins): void
{
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $allowedOrigins, true)) {
header("Access-Control-Allow-Origin: $origin");
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, Content-Type');
header('Access-Control-Max-Age: 86400');
}
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
}
Puis ajoutez ces lignes en haut de index.php, avant la ligne existante require 'auth0.php' :
require 'cors.php';
handleCors(['https://your-spa-domain.com']);
Le début actualisé de index.php devrait être :
<?php
require 'cors.php';
handleCors(['https://your-spa-domain.com']);
require 'auth0.php';
require 'middleware.php';
// ... reste d'index.php
CORS doit être traité avant l'authentification afin que les requêtes préflight OPTIONS s'arrêtent court sans déclencher la validation du token.
9. Tester l'API
Instruction agent : Démarrez le serveur PHP intégré et vérifiez que les endpoints basiques fonctionnent sans identifiants :
php -S localhost:8000 index.php & sleep 1 curl -s http://localhost:8000/api/public curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/api/private
/api/publicdevrait retourner{"message":"Public endpoint - no authentication required"}/api/privatedevrait retourner HTTP 401Si les deux tests passent, le middleware fonctionne. Tuez le serveur d'arrière-plan quand vous avez terminé :
kill %1 2>/dev/nullVérification d'échec : Si le serveur ne démarre pas ou
/api/publicgénère une erreur, vérifiez les problèmes de syntaxe PHP ou le fichier.envmanquant. Après 5-6 itérations d'échec, utilisezAskUserQuestionpour demander plus de détails à l'utilisateur sur son environnement.
Instruction agent : STOP - demandez après les tests basiques.
Une fois que les tests public/401 passent, demandez à l'utilisateur :
"Votre API est configurée et le middleware fonctionne (public retourne 200, private retourne 401 sans token). Souhaiteriez-vous que je vous aide à configurer des tests avec un vrai token d'accès ?
- Oui - Je vais vous aider à configurer une application M2M pour obtenir des tokens de test.
- Non - J'ai terminé pour maintenant.
Laquelle préférez-vous ?"
Ne procédez PAS à la configuration M2M/token à moins que l'utilisateur dise oui. S'il dit non, résumez ce qui a été fait et arrêtez.
Instruction agent (configuration app M2M - seulement si l'utilisateur veut des 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 l'ID client et je l'autoriserai pour cette API.
Laquelle préférez-vous ? (1 = Créer une nouvelle / 2 = Utiliser une existante)"
Ne procédez PAS jusqu'à ce que l'utilisateur réponde. Ne choisissez PAS silencieusement une application existante du tenant.
Si l'utilisateur a choisi "Créer une nouvelle" :
auth0 apps create \ --name "${PWD##*/} (Test App)" \ --type m2m \ --no-input --jsonParsez le JSON avec
jqpour extraireclient_id. N'utilisez PAS--reveal-secrets- n'exposez jamais les secrets client dans le contexte d'un agent. Puis créez une octroi client :auth0 api post "client-grants" --data '{ "client_id": "<CLIENT_ID>", "audience": "<API_IDENTIFIER>", "scope": ["<SCOPES>"] }'Si l'utilisateur a choisi "Utiliser une existante" : Demandez l'ID client. Puis créez une octroi client pour l'autoriser pour cette API :
auth0 api post "client-grants" --data '{ "client_id": "<USER_PROVIDED_CLIENT_ID>", "audience": "<API_IDENTIFIER>", "scope": ["<SCOPES>"] }'Si l'octroi existe déjà (409 conflit), c'est bon - l'app est déjà autorisée.
Instruction agent (ISOLATION DU TOKEN - CRITIQUE) :
L'agent ne DOIT JAMAIS voir directement ou afficher les valeurs des tokens d'accès. Règles de sécurité des tokens :
- N'exécutez PAS
auth0 test tokentout seul - il affiche le token en stdout- Ne demandez PAS à l'utilisateur de coller son token dans la conversation
- N'affichez PAS, n'imprimez PAS ou ne loggez PAS la valeur du token
- Ne stockez PAS le token dans un fichier
Approche de test sécurisée (chaîne de commande unique) :
Si l'utilisateur demande explicitement de tester les endpoints protégés, utilisez une chaîne de commande unique qui capture le token dans une variable shell et l'utilise immédiatement :
php -S localhost:8000 index.php & sleep 1 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)" && \ echo "=== GET /api/private ===" && \ curl -s http://localhost:8000/api/private -H "Authorization: Bearer $TEST_TOKEN" && \ echo "" && echo "=== GET /api/private-scoped ===" && \ curl -s http://localhost:8000/api/private-scoped -H "Authorization: Bearer $TEST_TOKEN" kill %1 2>/dev/nullRègles :
- Utilisez UNIQUEMENT quand l'utilisateur demande explicitement de tester
- Chaînez toujours l'acquisition du token + curl dans une SEULE commande
&&- N'ajoutez PAS
echo $TEST_TOKENou toute commande qui afficherait la valeur du token brut- Si l'acquisition du token échoue (variable vide), rapportez que l'app M2M n'est peut-être pas autorisée
- L'ID client est REQUIS - si la configuration M2M n'a pas été complétée, demandez d'abord à l'utilisateur
Si l'utilisateur NE demande PAS de tester, fournissez simplement les commandes pour qu'il les exécute manuellement :
auth0 test token <CLIENT_ID> --audience <AUDIENCE> --scopes <SCOPE1,SCOPE2> curl http://localhost:8000/api/private -H "Authorization: Bearer <PASTE_TOKEN_HERE>"
Démarrez le serveur :
php -S localhost:8000 index.php
Testez l'endpoint public (aucun token nécessaire) :
curl http://localhost:8000/api/public
Testez l'endpoint protégé sans token (devrait retourner 401) :
curl http://localhost:8000/api/private
Testez l'endpoint protégé avec token :
curl http://localhost:8000/api/private \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Testez l'endpoint avec scopes :
curl http://localhost:8000/api/private-scoped \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Obtenez un token de test via le tableau de bord Auth0 -> APIs -> onglet Test, ou via le flux M2M décrit ci-dessus.
Erreurs courantes
| Erreur | Correction |
|---|---|
Coder en dur domain ou audience dans le source |
Lisez toujours depuis les variables d'environnement - n'intégrez jamais les identifiants dans le code |
Utiliser STRATEGY_REGULAR pour une API |
Le mode API doit utiliser SdkConfiguration::STRATEGY_API - il désactive les sessions et cookies |
| Installer sans client HTTP PSR-18 | Doit avoir guzzlehttp/guzzle ou un autre client PSR-18 sinon le SDK ne peut pas récupérer JWKS |
| Ne pas cacher les clés JWKS | Sans un cache PSR-6, le SDK récupère JWKS à chaque requête - toujours configurer tokenCache |
Passer audience comme chaîne |
audience doit être un tableau : ['https://my-api.example.com'] pas 'https://my-api.example.com' |
Passer domain comme URL complète avec https:// |
domain doit être le domaine nu, par ex. my-tenant.us.auth0.com, pas https://my-tenant.us.auth0.com |
Utiliser decode() sans spécifier le type de token |
Toujours passer tokenType: Token::TYPE_ACCESS_TOKEN quand appeler decode() manuellement |
| Afficher les messages d'exception aux utilisateurs | Utilisez error_log() pour l'erreur réelle et retournez un message d'erreur JSON générique |
| Utiliser un ID token au lieu d'un token d'accès | Doit utiliser le token d'accès pour l'authentification API - les ID tokens sont pour l'app client |
| Créé une Application au lieu d'une API dans Auth0 | Doit créer une ressource API (Applications -> APIs) - une Application n'émet pas de tokens d'accès avec la bonne audience |
Définir clientId et s'attendre à ce que RS256 en ait besoin |
Pour RS256, clientId est optionnel - le SDK valide contre l'endpoint JWKS |
Utiliser clientSecret pour la validation RS256 |
clientSecret est requis seulement pour HS256 - RS256 utilise la clé publique depuis JWKS |
Passer $_SERVER directement à getBearerToken() |
Le param server prend un tableau de noms de clés à rechercher, par ex. ['HTTP_AUTHORIZATION'] - pas $_SERVER lui-même |
Méthodes clés du SDK
| Méthode | Retourne | But |
|---|---|---|
getBearerToken |
?TokenInterface |
Cherche un token Bearer dans les clés $_SERVER spécifiées, vérifie la signature, valide les claims. Retourne null si aucun token trouvé ou validation échouée (ne lève pas). |
decode |
TokenInterface |
Décode et valide manuellement une chaîne JWT |
configuration |
SdkConfiguration |
Accédez l'instance de configuration du SDK |
Token::toArray |
array |
Retourne tous les claims du token sous forme d'un tableau associatif |
Token::getSubject |
?string |
Retourne le claim sub (ID utilisateur/client) |
Token::getIssuer |
?string |
Retourne le claim iss |
Token::getAudience |
?array |
Retourne le claim aud |
Token::getExpiration |
?int |
Retourne le claim exp (timestamp Unix) |
Skills connexes
auth0-php- Pour les apps PHP web avec login/logout utilisant l'authentification basée sur les sessionsauth0-quickstart- Configuration Auth0 basique et détection de frameworkauth0-cli- Gérez les ressources Auth0 depuis le terminalauth0-mfa- Ajouter l'authentification multifacteur
Référence rapide
SdkConfiguration pour les APIs :
$configuration = new SdkConfiguration(
strategy: SdkConfiguration::STRATEGY_API, // requis - mode sans état
domain: $_ENV['AUTH0_DOMAIN'], // requis
audience: [$_ENV['AUTH0_AUDIENCE']], // requis - tableau d'identifiants
tokenAlgorithm: 'RS256', // par défaut
tokenCache: $psrCacheAdapter, // recommandé pour la production
tokenCacheTtl: 600, // TTL du cache JWKS en secondes
);
Validation du token :
$token = $auth0->getBearerToken(server: ['HTTP_AUTHORIZATION']); // retourne ?TokenInterface
$claims = $token->toArray(); // tous les claims sous forme de tableau
$userId = $token->getSubject(); // claim sub
Décode manuel :
use Auth0\SDK\Token;
$token = $auth0->decode(
$jwtString,
tokenType: Token::TYPE_ACCESS_TOKEN,
);
Variables d'environnement :
AUTH0_DOMAIN- votre domaine de tenant Auth0 (par ex.tenant.us.auth0.com)AUTH0_AUDIENCE- votre identifiant d'API (par ex.https://api.example.com)
Cas d'usage courants :
- Protéger les routes ->
requireAuth($auth0)(voir Étape 5) - Application des scopes ->
requireAuth($auth0, ['read:messages'])(voir Étape 5) - Configuration CORS -> Guide d'intégration
- Validation multi-audience -> Guide d'intégration
- Configuration avancée -> Référence API
Documentation détaillée
- Guide de configuration - Configuration Auth0 CLI, configuration de l'environnement, obtention de tokens de test
- Guide d'intégration - Scopes, permissions, middleware, multi-audience, CORS, gestion des erreurs
- Référence API - SDK API complet pour le mode API, options de configuration, méthodes de token