Passer au contenu principal

Utilisez l’IA pour intégrer Auth0

Si vous utilisez un assistant IA de programmation comme Claude Code, Cursor ou GitHub Copilot, vous pouvez ajouter automatiquement l’authentification Auth0 en quelques minutes à l’aide des agent skills.Installation :
npx skills add https://github.com/auth0/agent-skills --skill auth0-express
Demandez ensuite à votre assistant IA :
Add Auth0 authentication to my Express app
Votre assistant IA créera automatiquement votre application Auth0, récupérera les identifiants, installera express-openid-connect, configurera le middleware et mettra en place vos routes. Documentation complète des agent skills →
Prérequis : Avant de commencer, assurez-vous d’avoir installé les éléments suivants :
  • Node.js 18 LTS ou version ultérieure
  • npm 10+ ou yarn 1.22+
  • jq - Nécessaire pour configurer Auth0 CLI (facultatif)
Compatibilité des versions d’Express : Ce guide de démarrage rapide est compatible avec Express 4.17.0 et les versions ultérieures.

Premiers pas

Ce guide explique comment intégrer Auth0, ajouter l’authentification et afficher les informations du profil utilisateur dans une application Web Express.js à l’aide du SDK express-openid-connect.

1. Créez un nouveau projet

Créez un nouveau répertoire pour votre application Express, puis initialisez un projet Node.js.
mkdir auth0-express && cd auth0-express
npm init -y
Créez la structure du projet :
touch index.js .env

2. Installer le SDK Auth0 pour Express

Installez express-openid-connect ainsi qu’Express et dotenv pour gérer les variables d’environnement.
npm install express express-openid-connect dotenv
Pour le développement, installez nodemon pour redémarrer automatiquement votre serveur en cas de modification de fichiers :
npm install --save-dev nodemon
Mettez à jour votre package.json pour y ajouter des scripts de lancement : 📁 package.json
{
  "name": "auth0-express",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js"
  },
  "dependencies": {
    "dotenv": "^16.3.1",
    "express": "^4.18.2",
    "express-openid-connect": "^2.17.1"
  },
  "devDependencies": {
    "nodemon": "^3.0.2"
  }
}

3. Configurez votre application Auth0

Ensuite, vous devez créer une nouvelle application dans votre locataire Auth0 et ajouter les variables d’environnement à votre projet. Vous pouvez le faire automatiquement en exécutant une commande CLI ou manuellement dans l’Auth0 Dashboard :
Exécutez la commande shell suivante à la racine de votre projet pour créer une application Auth0 et générer votre fichier .env :macOS / Linux :
AUTH0_APP_NAME="My Express App" && \
auth0 apps create -n "${AUTH0_APP_NAME}" -t regular \
  --callbacks http://localhost:3000 \
  --logout-urls http://localhost:3000 \
  --json | jq -r '"ISSUER_BASE_URL=https://\(.domain)\nCLIENT_ID=\(.client_id)\nSECRET='$(openssl rand -hex 32)'\nBASE_URL=http://localhost:3000"' > .env
Windows (PowerShell) :
$appName = "My Express App"
auth0 apps create -n $appName -t regular `
  --callbacks http://localhost:3000 `
  --logout-urls http://localhost:3000 `
  --json | ConvertFrom-Json | ForEach-Object {
    "ISSUER_BASE_URL=https://$($_.domain)`nCLIENT_ID=$($_.client_id)`nSECRET=$([guid]::NewGuid().ToString())`nBASE_URL=http://localhost:3000"
  } | Out-File .env -Encoding utf8
Si vous n’avez pas encore installé Auth0 CLI, exécutez :
brew tap auth0/auth0-cli && brew install auth0
Authentifiez-vous ensuite avec auth0 login.

4. Configurez le middleware

Ajoutez le middleware Auth0 à votre application Express. Le middleware auth() assure la gestion des sessions et crée automatiquement les routes /login, /logout et /callback. 📁 index.js
require('dotenv').config();
const express = require('express');
const { auth } = require('express-openid-connect');

const app = express();
const port = process.env.PORT || 3000;

// Configuration Auth0
const config = {
  authRequired: false,      // Autoriser les routes publiques
  auth0Logout: true,        // Utiliser le point de terminaison de déconnexion Auth0
  secret: process.env.SECRET,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
};

// Appliquer le middleware d'authentification
app.use(auth(config));

// Route d'accueil - publique
app.get('/', (req, res) => {
  res.send(req.oidc.isAuthenticated() ? 'Logged in' : 'Logged out');
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});
Ce que cela fait :
  • authRequired: false permet, par défaut, aux utilisateurs authentifiés et non authentifiés d’accéder aux routes
  • auth0Logout: true garantit que les utilisateurs sont déconnectés d’Auth0 ainsi que de votre application
  • Le middleware fournit automatiquement les routes /login, /logout et /callback
  • La session de l’utilisateur est stockée dans un témoin chiffré

5. Créez les routes de connexion, de déconnexion et de profil

Ajoutez maintenant des routes pour afficher les liens de connexion et de déconnexion, ainsi qu’une page de profil protégée. 📁 index.js
require('dotenv').config();
const express = require('express');
const { auth, requiresAuth } = require('express-openid-connect');

const app = express();
const port = process.env.PORT || 3000;

// Configuration Auth0
const config = {
  authRequired: false,
  auth0Logout: true,
  secret: process.env.SECRET,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
};

// Appliquer le middleware d'authentification
app.use(auth(config));

// Route d'accueil - affiche le statut de connexion/déconnexion
app.get('/', (req, res) => {
  const isAuthenticated = req.oidc.isAuthenticated();

  res.send(`
    <html>
      <head>
        <title>Auth0 Express Quickstart</title>
        <style>
          body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 2rem; max-width: 600px; margin: 0 auto; }
          a { color: #0066cc; text-decoration: none; margin-right: 1rem; }
          a:hover { text-decoration: underline; }
          .status { padding: 1rem; border-radius: 4px; margin: 1rem 0; }
          .logged-in { background: #d4edda; color: #155724; }
          .logged-out { background: #f8d7da; color: #721c24; }
        </style>
      </head>
      <body>
        <h1>Auth0 Express Quickstart</h1>
        <div class="status ${isAuthenticated ? 'logged-in' : 'logged-out'}">
          ${isAuthenticated ? '✓ You are logged in' : '✗ You are logged out'}
        </div>
        <nav>
          ${isAuthenticated
            ? '<a href="/profile">Profile</a> | <a href="/logout">Logout</a>'
            : '<a href="/login">Login</a>'}
        </nav>
      </body>
    </html>
  `);
});

// Route de profil protégée - nécessite une authentification
app.get('/profile', requiresAuth(), (req, res) => {
  const user = req.oidc.user;

  res.send(`
    <html>
      <head>
        <title>Profile - Auth0 Express</title>
        <style>
          body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; padding: 2rem; max-width: 600px; margin: 0 auto; }
          a { color: #0066cc; text-decoration: none; }
          img { border-radius: 50%; }
          pre { background: #f4f4f4; padding: 1rem; border-radius: 4px; overflow-x: auto; }
          .card { border: 1px solid #ddd; border-radius: 8px; padding: 1.5rem; margin: 1rem 0; }
        </style>
      </head>
      <body>
        <h1>User Profile</h1>
        <div class="card">
          ${user.picture ? `<img src="${user.picture}" alt="Profile" width="80" />` : ''}
          <h2>${user.name || user.nickname || 'User'}</h2>
          <p><strong>Email:</strong> ${user.email || 'N/A'}</p>
        </div>
        <h3>Full User Object</h3>
        <pre>${JSON.stringify(user, null, 2)}</pre>
        <nav>
          <a href="/">← Back to Home</a> | <a href="/logout">Logout</a>
        </nav>
      </body>
    </html>
  `);
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});
Points clés :
  • Le middleware requiresAuth() protège la route /profile : les utilisateurs non authentifiés sont redirigés vers la page de connexion
  • req.oidc.user contient les informations de profil de l’utilisateur authentifié
  • req.oidc.isAuthenticated() retourne un booléen indiquant l’état de la connexion
  • Les routes de connexion et de déconnexion (/login, /logout) sont créées automatiquement par le middleware auth()

6. Exécutez votre application

Démarrez le serveur de développement :
npm run dev
Ouvrez http://localhost:3000 dans votre navigateur.
Point de vérificationVous devriez maintenant disposer d’une page de connexion Auth0 entièrement fonctionnelle. Lorsque vous :
  1. Cliquez sur “Login” - vous êtes redirigé vers la page Universal Login d’Auth0
  2. Terminez l’authentification - vous êtes redirigé vers votre application
  3. Accédez à “/profile” - vous voyez vos informations d’utilisateur
  4. Cliquez sur “Logout” - vous êtes déconnecté à la fois de votre application et d’Auth0

Utilisation avancée

Utilisez le middleware requiresAuth() pour protéger chaque route qui nécessite une authentification :
const { auth, requiresAuth } = require('express-openid-connect');

app.use(auth({ authRequired: false }));

// Route publique
app.get('/', (req, res) => {
  res.send('Welcome! This is public.');
});

// Routes protégées
app.get('/dashboard', requiresAuth(), (req, res) => {
  res.send(`Hello ${req.oidc.user.name}, welcome to your dashboard!`);
});

app.get('/settings', requiresAuth(), (req, res) => {
  res.send('Settings page - only for authenticated users');
});
Vous pouvez également protéger toutes les routes d’un chemin donné à l’aide d’Express Router :
const protectedRouter = express.Router();

// Toutes les routes de ce routeur nécessitent une authentification
protectedRouter.use(requiresAuth());

protectedRouter.get('/dashboard', (req, res) => {
  res.send('Protected dashboard');
});

protectedRouter.get('/settings', (req, res) => {
  res.send('Protected settings');
});

app.use('/app', protectedRouter);
// Routes : /app/dashboard, /app/settings sont toutes protégées
Pour appeler des API externes qui nécessitent un jeton d’accès, configurez le SDK pour en demander un :📁 index.js (configuration mise à jour)
const config = {
  authRequired: false,
  auth0Logout: true,
  secret: process.env.SECRET,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
  clientSecret: process.env.CLIENT_SECRET,  // Requis pour le flux de code
  authorizationParams: {
    response_type: 'code',
    audience: process.env.API_AUDIENCE,     // Your API identifier
    scope: 'openid profile email read:data',
  },
};
Ajoutez les éléments suivants à votre fichier .env :
CLIENT_SECRET=your_client_secret_from_dashboard
API_AUDIENCE=https://your-api.example.com
Utilisez ensuite le jeton d’accès pour appeler votre API :
app.get('/api-data', requiresAuth(), async (req, res) => {
  try {
    let { token_type, access_token, isExpired, refresh } = req.oidc.accessToken;

    // Actualiser le jeton s'il est expiré
    if (isExpired()) {
      const refreshed = await refresh();
      access_token = refreshed.access_token;
    }

    // Appeler votre API protégée
    const response = await fetch('https://your-api.example.com/data', {
      headers: {
        Authorization: `${token_type} ${access_token}`,
      },
    });

    const data = await response.json();
    res.json(data);
  } catch (error) {
    console.error('API call failed:', error);
    res.status(500).json({ error: 'Failed to fetch data' });
  }
});
Pour obtenir des jetons d’actualisation, ajoutez offline_access à votre scope :
scope: 'openid profile email offline_access read:data',
Protégez les routes selon les claim de l’utilisateur (rôles, autorisations, etc.):
const { auth, requiresAuth, claimEquals, claimIncludes, claimCheck } = require('express-openid-connect');

app.use(auth({ authRequired: false }));

// Uniquement les utilisateurs avec le rôle = 'admin'
app.get('/admin', claimEquals('role', 'admin'), (req, res) => {
  res.send('Admin dashboard');
});

// Utilisateurs dont le tableau de rôles contient 'editor'
app.get('/editor', claimIncludes('roles', 'editor'), (req, res) => {
  res.send('Editor dashboard');
});

// Vérification de revendication personnalisée avec logique
app.get('/premium', claimCheck((req, claims) => {
  return claims.subscription === 'premium' || claims.role === 'admin';
}), (req, res) => {
  res.send('Premium content');
});
Les revendications comme role doivent être ajoutées à vos jetons au moyen des Rules ou des Actions d’Auth0. En savoir plus sur l’ajout de revendications personnalisées.
Pour les environnements de production, ou lorsque vous exécutez plusieurs instances de serveur, utilisez un stockage de session personnalisé :
npm install redis connect-redis
const { auth } = require('express-openid-connect');
const { createClient } = require('redis');
const RedisStore = require('connect-redis').default;

// Créer le client Redis
const redisClient = createClient({
  url: process.env.REDIS_URL || 'redis://localhost:6379',
});
redisClient.connect().catch(console.error);

const config = {
  authRequired: false,
  auth0Logout: true,
  secret: process.env.SECRET,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
  session: {
    store: new RedisStore({ client: redisClient }),
  },
};

app.use(auth(config));
Quand utiliser un stockage de sessions personnalisé :
  • Exécution de plusieurs instances de serveur (répartition de charge)
  • Les données de session dépassent la taille limite d’un témoin (~4 KB)
  • Besoin de conserver les sessions entre les redémarrages du serveur
  • Utilisation de la déconnexion par canal arrière
Ajoutez une gestion appropriée des erreurs d’authentification :
const { auth } = require('express-openid-connect');

app.use(auth({
  authRequired: false,
  auth0Logout: true,
  secret: process.env.SECRET,
  baseURL: process.env.BASE_URL,
  clientID: process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
  errorOnRequiredAuth: true,  // Renvoyer 401 au lieu de rediriger pour les routes API
}));

// Gestionnaire d'erreurs personnalisé
app.use((err, req, res, next) => {
  // Gérer les erreurs d'authentification
  if (err.statusCode === 401) {
    // Pour les requêtes API, renvoyer du JSON
    if (req.accepts('json')) {
      return res.status(401).json({
        error: 'Authentication required',
        login_url: '/login',
      });
    }
    // Pour les requêtes du navigateur, rediriger vers la page de connexion
    return res.redirect('/login');
  }

  // Journaliser l'erreur (ne pas exposer les détails au client)
  console.error('Application error:', err.message);

  res.status(err.statusCode || 500).json({
    error: 'An unexpected error occurred',
  });
});

Dépannage

Erreur « Invalid state » après la connexion

Problème : Le paramètre state ne correspond pas entre la requête d’authentification et le callback.Solutions :
  1. Assurez-vous d’utiliser HTTPS en production
  2. Vérifiez que les témoins sont correctement définis (et non bloqués par le navigateur)
  3. Vérifiez que l’URL de retour correspond exactement dans Auth0 Dashboard

req.oidc est undefined

Problème : Le middleware auth() n’est pas appliqué avant l’accès à req.oidc.Solution : Assurez-vous que app.use(auth(config)) est appelé avant toute route qui accède à req.oidc :
// ✅ Ordre correct
app.use(auth(config));
app.get('/profile', requiresAuth(), (req, res) => { ... });

// ❌ Mauvais ordre
app.get('/profile', requiresAuth(), (req, res) => { ... });
app.use(auth(config));

Session trop volumineuse / erreurs liées aux témoins

Problème : Les données de session de l’utilisateur dépassent la taille limite des témoins.Solution : Utilisez un stockage de session personnalisé, comme Redis :
session: {
  store: new RedisStore({ client: redisClient }),
}

URL de retour non correspondante

Problème : Erreur « Callback URL mismatch » renvoyée par Auth0.Solution :
  1. Accédez à Auth0 Dashboard → Applications → Votre application → Settings
  2. Ajoutez http://localhost:3000 (ou votre URL de production) à Allowed Callback URLs
  3. L’URL doit correspondre exactement (y compris les barres obliques finales)

Les variables d’environnement ne se chargent pas

Problème : Les valeurs de configuration sont undefined.Solution :
  1. Assurez-vous que require('dotenv').config() se trouve en haut de votre fichier d’entrée
  2. Vérifiez que le fichier .env se trouve dans le répertoire racine
  3. Vérifiez qu’il n’y a pas de fautes de frappe dans les noms de variables
// Débogage : consignez les valeurs de configuration (à supprimer en production !)
console.log('Config check:', {
  hasSecret: !!process.env.SECRET,
  hasClientID: !!process.env.CLIENT_ID,
  issuerBaseURL: process.env.ISSUER_BASE_URL,
});

Étapes suivantes

Maintenant que l’authentification fonctionne, vous pouvez aussi explorer :

Ressources