Intégration Auth0 PHP Web App
Ajoutez connexion, déconnexion et profil utilisateur à une application web PHP en utilisant auth0/auth0-php.
Prérequis
- PHP 8.2+ avec extensions :
mbstring,openssl,json - Composer installé
- Application Web Auth0 Regular Web Application configurée (pas une API - doit être une Application)
- Si Auth0 n'est pas encore configuré, utilisez d'abord la skill
auth0-quickstart
Quand NE PAS l'utiliser
- PHP APIs avec validation JWT Bearer - Utilisez
auth0-php-apipour la validation de tokens d'API sans état - Applications Laravel - Utilisez une intégration Laravel dédiée avec
auth0/laravel-auth0 - Applications Symfony - Utilisez une intégration Symfony dédiée avec
auth0/symfony - Applications monopage - Utilisez
auth0-react,auth0-vueouauth0-angularpour l'auth côté client - Applications Next.js - Utilisez
auth0-nextjsqui gère client et serveur - Applications web Node.js - Utilisez
auth0-expressouauth0-fastifypour l'auth basée sur les sessions
Workflow Démarrage Rapide
1. Installer le SDK
composer require auth0/auth0-php vlucas/phpdotenv guzzlehttp/guzzle guzzlehttp/psr7
auth0/auth0-php- Le SDK Auth0vlucas/phpdotenv- Charge les fichiers.envdans$_ENVguzzlehttp/guzzle+guzzlehttp/psr7- Client HTTP PSR-18 requis par le SDK
2. Configurer l'environnement
Créez .env :
AUTH0_DOMAIN=your-tenant.us.auth0.com
AUTH0_CLIENT_ID=your_client_id
AUTH0_CLIENT_SECRET=your_client_secret
AUTH0_COOKIE_SECRET=your_generated_secret
AUTH0_REDIRECT_URI=http://localhost:3000/callback
AUTH0_DOMAIN est votre domaine de tenant Auth0 (sans https://). AUTH0_CLIENT_ID et AUTH0_CLIENT_SECRET proviennent des paramètres de votre Application Auth0. AUTH0_COOKIE_SECRET est utilisé pour chiffrer les cookies de session - générez avec openssl rand -hex 32.
3. Configurer le Dashboard Auth0
Dans les paramètres de votre Application Auth0 :
- Application Type : Regular Web Application
- Allowed Callback URLs :
http://localhost:3000/callback - Allowed Logout URLs :
http://localhost:3000
4. Créer la configuration Auth
Créez auth0.php pour initialiser le SDK :
<?php
require 'vendor/autoload.php';
use Auth0\SDK\Auth0;
use Auth0\SDK\Configuration\SdkConfiguration;
// Load environment variables
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
$configuration = new SdkConfiguration(
strategy: SdkConfiguration::STRATEGY_REGULAR,
domain: $_ENV['AUTH0_DOMAIN'],
clientId: $_ENV['AUTH0_CLIENT_ID'],
clientSecret: $_ENV['AUTH0_CLIENT_SECRET'],
cookieSecret: $_ENV['AUTH0_COOKIE_SECRET'],
redirectUri: $_ENV['AUTH0_REDIRECT_URI'],
scope: ['openid', 'profile', 'email'],
);
$auth0 = new Auth0($configuration);
Créez une seule instance Auth0 et réutilisez-la. Ne codez jamais les identifiants en dur - utilisez toujours les variables d'environnement.
Fonctionnement : Le SDK chiffre les données de session (tokens, profil utilisateur) en utilisant AES-256-GCM avec une clé dérivée de cookieSecret via HKDF-SHA256. Les données de session sont stockées dans un cookie chiffré par défaut - aucune base de données côté serveur requise.
5. Créer la page d'accueil (Router)
Créez index.php comme simple contrôleur frontal. Créez d'abord le répertoire routes/ :
<?php
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
if ($path === '/style.css') {
header('Content-Type: text/css');
readfile(__DIR__ . '/style.css');
exit;
}
require 'auth0.php';
switch ($path) {
case '/':
require 'routes/home.php';
break;
case '/login':
require 'routes/login.php';
break;
case '/callback':
require 'routes/callback.php';
break;
case '/profile':
require 'routes/profile.php';
break;
case '/logout':
require 'routes/logout.php';
break;
default:
http_response_code(404);
echo 'Not found';
break;
}
Le gestionnaire de fichiers statiques pour /style.css est placé avant require 'auth0.php' afin que les feuilles de style se chargent sans initialiser le SDK.
6. Ajouter la feuille de style
Créez style.css :
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f5f7fa;
color: #1a1a2e;
line-height: 1.6;
min-height: 100vh;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 40px 20px;
}
.card {
background: #fff;
border-radius: 12px;
padding: 28px;
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
border: 1px solid #e8ecf0;
}
.card.center {
text-align: center;
padding: 60px 28px;
}
h1 {
font-size: 1.5rem;
font-weight: 600;
margin-bottom: 4px;
}
h2 {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: 16px;
color: #444;
}
.subtitle {
color: #666;
font-size: 0.95rem;
}
.card.center .subtitle {
margin: 12px 0 28px;
}
.user-header {
display: flex;
align-items: center;
gap: 16px;
}
.avatar {
width: 48px;
height: 48px;
border-radius: 50%;
object-fit: cover;
}
.avatar-lg {
width: 72px;
height: 72px;
}
.nav-links {
margin-top: 20px;
display: flex;
gap: 12px;
}
.top-nav {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.btn {
display: inline-block;
padding: 10px 20px;
border-radius: 8px;
text-decoration: none;
font-size: 0.9rem;
font-weight: 500;
transition: all 0.15s ease;
}
.btn-primary {
background: #635bff;
color: #fff;
}
.btn-primary:hover {
background: #4b44d4;
}
.btn-secondary {
background: #f0f0f5;
color: #444;
}
.btn-secondary:hover {
background: #e4e4ec;
}
.btn-back {
background: none;
color: #635bff;
padding: 10px 0;
}
.btn-back:hover {
color: #4b44d4;
}
.info-table {
width: 100%;
border-collapse: collapse;
}
.info-table tr {
border-bottom: 1px solid #f0f0f5;
}
.info-table tr:last-child {
border-bottom: none;
}
.info-table td {
padding: 10px 0;
vertical-align: top;
}
.info-table .label {
font-weight: 500;
color: #666;
width: 160px;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.02em;
}
.info-table .value {
color: #1a1a2e;
word-break: break-all;
}
.token-box {
background: #f8f9fb;
border: 1px solid #e8ecf0;
border-radius: 8px;
padding: 14px;
font-size: 0.8rem;
font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
word-break: break-all;
white-space: pre-wrap;
max-height: 120px;
overflow-y: auto;
margin-bottom: 16px;
}
7. Ajouter la route d'accueil
Créez routes/home.php :
<?php
$credentials = $auth0->getCredentials();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Auth0 PHP App</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<div class="container">
<?php if ($credentials): ?>
<div class="card">
<div class="user-header">
<img src="<?= htmlspecialchars($credentials->user['picture'] ?? '') ?>" alt="avatar" class="avatar" />
<div>
<h1>Hello, <?= htmlspecialchars($credentials->user['name'] ?? 'User') ?>!</h1>
<p class="subtitle"><?= htmlspecialchars($credentials->user['email'] ?? '') ?></p>
</div>
</div>
<nav class="nav-links">
<a href="/profile" class="btn btn-primary">View Profile & Tokens</a>
<a href="/logout" class="btn btn-secondary">Logout</a>
</nav>
</div>
<?php else: ?>
<div class="card center">
<h1>Auth0 PHP Web App</h1>
<p class="subtitle">Session-based authentication with Auth0 SDK</p>
<a href="/login" class="btn btn-primary">Login</a>
</div>
<?php endif; ?>
</div>
</body>
</html>
8. Ajouter la route de connexion
Créez routes/login.php :
<?php
header('Location: ' . $auth0->login());
exit;
login() retourne une URL string pointant vers la page Universal Login d'Auth0. Vous devez rediriger l'utilisateur vers celle-ci.
9. Ajouter la route callback
Créez routes/callback.php :
<?php
if (null !== $auth0->getExchangeParameters()) {
try {
$auth0->exchange();
header('Location: /');
exit;
} catch (\Exception $e) {
error_log('Auth0 callback error: ' . $e->getMessage());
http_response_code(400);
echo "Authentication failed. Please try again.";
exit;
}
}
header('Location: /');
exit;
getExchangeParameters() vérifie si le callback contient des paramètres de code d'autorisation. exchange() échange le code contre des tokens et établit la session. Enveloppez toujours dans try/catch car l'échange de token peut échouer (par ex. code expiré, non-correspondance CSRF).
10. Ajouter la route de profil (Protégée)
Créez routes/profile.php :
<?php
$credentials = $auth0->getCredentials();
if (null === $credentials) {
header('Location: /login');
exit;
}
$user = $credentials->user;
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Profile - Auth0 PHP App</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<div class="container">
<nav class="top-nav">
<a href="/" class="btn btn-back">← Back to Home</a>
<a href="/logout" class="btn btn-secondary">Logout</a>
</nav>
<div class="card">
<div class="user-header">
<img src="<?= htmlspecialchars($user['picture'] ?? '') ?>" alt="avatar" class="avatar avatar-lg" />
<div>
<h1><?= htmlspecialchars($user['name'] ?? 'User') ?></h1>
<p class="subtitle"><?= htmlspecialchars($user['email'] ?? '') ?></p>
</div>
</div>
</div>
<div class="card">
<h2>User Profile Claims</h2>
<table class="info-table">
<?php foreach ($user as $key => $value): ?>
<tr>
<td class="label"><?= htmlspecialchars($key) ?></td>
<td class="value"><?= htmlspecialchars(is_array($value) ? json_encode($value) : (string)$value) ?></td>
</tr>
<?php endforeach; ?>
</table>
</div>
<div class="card">
<h2>ID Token</h2>
<pre class="token-box"><?= htmlspecialchars($credentials->idToken ?? 'N/A') ?></pre>
</div>
<div class="card">
<h2>Access Token</h2>
<pre class="token-box"><?= htmlspecialchars($credentials->accessToken ?? 'N/A') ?></pre>
<table class="info-table">
<tr>
<td class="label">Expires</td>
<td class="value"><?= $credentials->accessTokenExpiration ? date('Y-m-d H:i:s', $credentials->accessTokenExpiration) . ' (' . ($credentials->accessTokenExpired ? 'EXPIRED' : 'valid') . ')' : 'N/A' ?></td>
</tr>
<tr>
<td class="label">Scopes</td>
<td class="value"><?= htmlspecialchars(implode(', ', $credentials->accessTokenScope ?? [])) ?></td>
</tr>
</table>
</div>
<?php if ($credentials->refreshToken): ?>
<div class="card">
<h2>Refresh Token</h2>
<pre class="token-box"><?= htmlspecialchars($credentials->refreshToken) ?></pre>
</div>
<?php endif; ?>
</div>
</body>
</html>
getCredentials() retourne les données de session de l'utilisateur, ou null s'il n'est pas connecté. La page de profil affiche toutes les revendications d'utilisateur et les tokens pour vérification lors du développement.
11. Ajouter la route de déconnexion
Créez routes/logout.php :
<?php
header('Location: ' . $auth0->logout(returnUri: 'http://localhost:3000'));
exit;
logout() retourne l'URL de déconnexion Auth0. Redirigez l'utilisateur vers celle-ci. Le returnUri est l'endroit où Auth0 envoie l'utilisateur après la déconnexion - il doit être listé dans Allowed Logout URLs. En production, remplacez par votre domaine réel.
12. Tester l'application
php -S localhost:3000 index.php
Visitez http://localhost:3000/login pour démarrer le flux de connexion.
Erreurs Courantes
| Erreur | Correction |
|---|---|
Codage en dur de domain, clientId ou clientSecret dans le code source |
Lisez toujours depuis les variables d'environnement - ne plongez jamais les identifiants dans le code |
Utilisation d'une ancienne version auth0-PHP < 8.0 |
Requérez PHP 8.2+ et la v8.x du SDK ; les anciennes versions ont des APIs différentes |
| Installation sans client HTTP PSR-18 | Doit avoir un client PSR-18 (par ex. guzzlehttp/guzzle) ou le SDK ne peut pas faire de requêtes HTTP |
Utilisation de STRATEGY_API pour une application web |
Les applications web doivent utiliser SdkConfiguration::STRATEGY_REGULAR pour l'auth basée sur les sessions |
Passage de 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 |
Oubli de cookieSecret |
Requis pour le chiffrement de session - sans lui, le SDK lève une ConfigurationException |
Non-vérification de getExchangeParameters() avant exchange() |
Appeler exchange() sans paramètres cause des erreurs ; vérifiez toujours d'abord |
| Non-gestion des erreurs dans le callback | exchange() peut échouer - enveloppez toujours dans try/catch |
| Application créée comme type SPA dans Auth0 | Doit être du type Regular Web Application pour l'auth côté serveur |
| Non-configuration de l'URL callback dans le Dashboard Auth0 | Doit ajouter http://localhost:3000/callback à Allowed Callback URLs |
Utilisation directe de $_SESSION |
Le SDK gère sa propre session de cookie chiffré - n'utilisez pas $_SESSION sauf si vous configurez un SessionStore personnalisé |
Déploiement sans cookieSecure: true |
Doit être mis à true en production - les cookies sont envoyés sur HTTP sinon |
Appel de login() ou logout() sans redirection |
Les deux retournent des strings URL, pas des réponses - doit utiliser header('Location: ...') |
| "Network error resulted in unfulfilled request" au callback | Signifie généralement que AUTH0_CLIENT_SECRET est incorrect, pas un réel problème réseau - vérifiez vos identifiants dans .env |
Méthodes SDK clés
| Méthode | Signature | Objectif |
|---|---|---|
login |
$auth0->login(?string $redirectUrl, ?array $params): string |
Retourne une string d'URL d'autorisation - redirigez l'utilisateur vers celle-ci |
exchange |
$auth0->exchange(?string $redirectUri, ?string $code, ?string $state): bool |
Échange le code d'autorisation contre des tokens, établit la session |
getCredentials |
$auth0->getCredentials(): ?object |
Retourne les identifiants de session actuels ou null |
getExchangeParameters |
$auth0->getExchangeParameters(): ?object |
Vérifie si le callback contient les paramètres d'échange |
logout |
$auth0->logout(?string $returnUri, ?array $params): string |
Retourne la string d'URL de déconnexion Auth0 |
renew |
$auth0->renew(?array $params): self |
Rafraîchit le token d'accès expiré (requiert le scope offline_access) |
clear |
$auth0->clear(bool $transient = true): self |
Efface la session locale sans déconnexion Auth0 |
Objet Credentials
Après une authentification réussie, getCredentials() retourne un objet avec :
$credentials = $auth0->getCredentials();
$credentials->user; // array - revendications du profil utilisateur
$credentials->idToken; // string - token ID brut
$credentials->accessToken; // string - token d'accès
$credentials->refreshToken; // string|null - token d'actualisation (requiert offline_access)
$credentials->accessTokenExpiration; // int - timestamp d'expiration
$credentials->accessTokenExpired; // bool - si le token est expiré
$credentials->accessTokenScope; // array - scopes accordés
Revendications du profil utilisateur ($credentials->user) :
sub- identifiant utilisateur uniquename,nickname,pictureemail,email_verifiedgiven_name,family_nameupdated_at,locale
Skills Connexes
auth0-php-api- Pour protéger les APIs PHP avec validation de token Bearer JWTauth0-quickstart- Configuration Auth0 basique et détection de frameworkauth0-cli- Gérer les ressources Auth0 depuis le terminalauth0-mfa- Ajouter l'authentification multi-facteurs
Référence Rapide
SdkConfiguration pour les applications web :
$configuration = new SdkConfiguration(
strategy: SdkConfiguration::STRATEGY_REGULAR, // required
domain: $_ENV['AUTH0_DOMAIN'], // required
clientId: $_ENV['AUTH0_CLIENT_ID'], // required
clientSecret: $_ENV['AUTH0_CLIENT_SECRET'], // required
cookieSecret: $_ENV['AUTH0_COOKIE_SECRET'], // required
redirectUri: $_ENV['AUTH0_REDIRECT_URI'], // required
scope: ['openid', 'profile', 'email'], // recommended
);
Modèle de protection de route :
$credentials = $auth0->getCredentials();
if (null === $credentials) {
header('Location: /login');
exit;
}
Variables d'environnement :
AUTH0_DOMAIN- votre domaine de tenant Auth0 (par ex.tenant.us.auth0.com)AUTH0_CLIENT_ID- ID client de votre ApplicationAUTH0_CLIENT_SECRET- secret client de votre ApplicationAUTH0_COOKIE_SECRET- clé secrète de chiffrement (générez :openssl rand -hex 32)AUTH0_REDIRECT_URI- URL de callback (par ex.http://localhost:3000/callback)
Documentation Détaillée
- Setup Guide - Scripts de configuration automatisée, configuration d'environnement, utilisation de l'Auth0 CLI
- Integration Guide - Routes protégées, appel d'APIs, gestion de session, gestion des erreurs
- API Reference - API SDK Auth0 complète, options de configuration, stockage de session, sécurité