Passer au contenu principal

Utiliser l’IA pour intégrer Auth0

Si vous utilisez un assistant de codage IA comme Claude Code, Cursor ou GitHub Copilot, vous pouvez ajouter automatiquement l’authentification Auth0 en quelques minutes à l’aide des agent skills.Installer :
npx skills add auth0/agent-skills --skill auth0-quickstart --skill auth0-fastify
Ensuite, demandez à votre assistant IA :
Add Auth0 authentication to my Fastify app
Votre assistant IA créera automatiquement votre application Auth0, récupérera les identifiants, installera @auth0/auth0-fastify, configurera le plugin et créera toutes les routes et vues nécessaires. Documentation complète des agent skills →
Prérequis : Avant de commencer, assurez-vous d’avoir installé les éléments suivants :Vérifiez l’installation : node --version && npm --versionCompatibilité des versions de Fastify : Ce guide de démarrage rapide fonctionne avec Fastify 5.x et les versions ultérieures.

Premiers pas

Ce guide de démarrage rapide explique comment intégrer l’authentification Auth0 à une application Fastify. Vous créerez une application web sécurisée avec des fonctionnalités de connexion, de déconnexion et de profil utilisateur à l’aide du SDK Fastify d’Auth0.
1

Créer un nouveau projet

Créez un nouveau dossier pour votre application Fastify et initialisez un projet Node.js.
mkdir auth0-fastify && cd auth0-fastify
Initialisez le projet
npm init -y
Créez la structure du projet
touch server.js .env
2

Installer le SDK Auth0 pour Fastify

Installez les dépendances requises
npm install @auth0/auth0-fastify fastify dotenv @fastify/view ejs
Nous utilisons @fastify/view avec ejs pour le rendu côté serveur. Vous pouvez utiliser n’importe quel moteur de modèles pris en charge par Fastify.
Mettez à jour votre package.json pour y ajouter des scripts de démarrage :
package.json
{
  "name": "auth0-fastify",
  "version": "1.0.0",
  "type": "module",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "dev": "node --watch server.js"
  },
  "dependencies": {
    "@auth0/auth0-fastify": "^1.2.0",
    "@fastify/view": "^10.0.0",
    "dotenv": "^16.3.1",
    "ejs": "^3.1.9",
    "fastify": "^5.0.0"
  }
}
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 avez trois options pour configurer votre application Auth0 : utiliser l’outil de configuration rapide (recommandé), exécuter une commande CLI ou faire la configuration manuellement dans l’Auth0 Dashboard :
Créez une application Auth0 et copiez le fichier .env prérempli avec les bonnes valeurs de configuration.
Vérifiez que votre fichier .env existe : cat .env (Mac/Linux) ou type .env (Windows)
4

Configurer le plugiciel Auth0

Créez votre serveur Fastify et enregistrez le module d’extension Auth0 :
server.js
import 'dotenv/config';
import Fastify from 'fastify';
import fastifyView from '@fastify/view';
import fastifyAuth0 from '@auth0/auth0-fastify';
import ejs from 'ejs';

const fastify = Fastify({ logger: true });
const port = process.env.PORT || 3000;

// Enregistrer le moteur de vue
await fastify.register(fastifyView, {
  engine: { ejs },
  root: './views',
});

// Enregistrer le plugin Auth0
await fastify.register(fastifyAuth0, {
  domain: process.env.AUTH0_DOMAIN,
  clientId: process.env.AUTH0_CLIENT_ID,
  clientSecret: process.env.AUTH0_CLIENT_SECRET,
  appBaseUrl: process.env.APP_BASE_URL,
  sessionSecret: process.env.SESSION_SECRET,
});

// Démarrer le serveur
fastify.listen({ port }, (err) => {
  if (err) {
    fastify.log.error(err);
    process.exit(1);
  }
  fastify.log.info(`Server running at http://localhost:${port}`);
});
Ce que cela fait :
  • Enregistre le moteur de vues pour le rendu de modèles HTML
  • Configure le plugin Auth0 avec vos identifiants
  • Crée automatiquement des routes sur /auth/login, /auth/logout et /auth/callback
  • Gère les sessions à l’aide de témoins chiffrés
5

Créer des gabarits de vue

Créez un répertoire views et ajoutez des fichiers de gabarit :
Mac/Linux
mkdir views && touch views/home.ejs views/profile.ejs
Windows
New-Item -ItemType Directory -Path views
New-Item -ItemType File -Path views/home.ejs
New-Item -ItemType File -Path views/profile.ejs
Créez le modèle de page d’accueil :
views/home.ejs
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Auth0 Fastify Quickstart</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      margin: 0;
      padding: 2rem;
      min-height: 100vh;
      display: flex;
      justify-content: center;
      align-items: center;
    }
    .container {
      background: white;
      border-radius: 20px;
      box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
      padding: 3rem;
      max-width: 500px;
      width: 100%;
      text-align: center;
    }
    h1 {
      color: #2d3748;
      font-size: 2.5rem;
      margin-bottom: 1rem;
    }
    .status {
      padding: 1rem;
      border-radius: 10px;
      margin: 1.5rem 0;
      font-size: 1.1rem;
    }
    .logged-in {
      background: #d4edda;
      color: #155724;
    }
    .logged-out {
      background: #f8d7da;
      color: #721c24;
    }
    .button {
      display: inline-block;
      padding: 1rem 2rem;
      margin: 0.5rem;
      border-radius: 10px;
      text-decoration: none;
      font-weight: 600;
      transition: all 0.3s;
    }
    .button-primary {
      background: #667eea;
      color: white;
    }
    .button-primary:hover {
      background: #5568d3;
      transform: translateY(-2px);
    }
    .button-secondary {
      background: #e53e3e;
      color: white;
    }
    .button-secondary:hover {
      background: #c53030;
      transform: translateY(-2px);
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>🚀 Auth0 Fastify</h1>
    <div class="status <%= isAuthenticated ? 'logged-in' : 'logged-out' %>">
      <%= isAuthenticated ? '✓ You are logged in' : '✗ You are logged out' %>
    </div>
    <div>
      <% if (isAuthenticated) { %>
        <a href="/profile" class="button button-primary">View Profile</a>
        <a href="/auth/logout" class="button button-secondary">Logout</a>
      <% } else { %>
        <a href="/auth/login" class="button button-primary">Login</a>
      <% } %>
    </div>
  </div>
</body>
</html>
Créez le modèle de page de profil :
views/profile.ejs
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Profile - Auth0 Fastify</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      margin: 0;
      padding: 2rem;
      min-height: 100vh;
    }
    .container {
      background: white;
      border-radius: 20px;
      box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
      padding: 3rem;
      max-width: 700px;
      margin: 0 auto;
    }
    h1 {
      color: #2d3748;
      margin-bottom: 2rem;
    }
    .profile-card {
      display: flex;
      align-items: center;
      gap: 2rem;
      padding: 2rem;
      background: #f7fafc;
      border-radius: 15px;
      margin-bottom: 2rem;
    }
    .profile-picture {
      width: 100px;
      height: 100px;
      border-radius: 50%;
      object-fit: cover;
      border: 3px solid #667eea;
    }
    .profile-info h2 {
      margin: 0 0 0.5rem 0;
      color: #2d3748;
    }
    .profile-info p {
      margin: 0;
      color: #718096;
    }
    .user-data {
      background: #f7fafc;
      padding: 1.5rem;
      border-radius: 10px;
      overflow-x: auto;
    }
    pre {
      margin: 0;
      white-space: pre-wrap;
      word-wrap: break-word;
    }
    .button {
      display: inline-block;
      padding: 0.75rem 1.5rem;
      margin-right: 1rem;
      border-radius: 10px;
      text-decoration: none;
      font-weight: 600;
      transition: all 0.3s;
    }
    .button-primary {
      background: #667eea;
      color: white;
    }
    .button-primary:hover {
      background: #5568d3;
    }
    .button-secondary {
      background: #e53e3e;
      color: white;
    }
    .button-secondary:hover {
      background: #c53030;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>User Profile</h1>
    <div class="profile-card">
      <img src="<%= user.picture || 'https://via.placeholder.com/100' %>" alt="Profile" class="profile-picture">
      <div class="profile-info">
        <h2><%= user.name || user.nickname || 'User' %></h2>
        <p><strong>Email:</strong> <%= user.email || 'N/A' %></p>
      </div>
    </div>
    <h3>Full User Object</h3>
    <div class="user-data">
      <pre><%= JSON.stringify(user, null, 2) %></pre>
    </div>
    <div style="margin-top: 2rem;">
      <a href="/" class="button button-primary">← Back to Home</a>
      <a href="/auth/logout" class="button button-secondary">Logout</a>
    </div>
  </div>
</body>
</html>
6

Créer des routes

Ajoutez des routes à votre fichier server.js :
server.js
import 'dotenv/config';
import Fastify from 'fastify';
import fastifyView from '@fastify/view';
import fastifyAuth0 from '@auth0/auth0-fastify';
import ejs from 'ejs';

const fastify = Fastify({ logger: true });
const port = process.env.PORT || 3000;

// Enregistrer le moteur de vue
await fastify.register(fastifyView, {
  engine: { ejs },
  root: './views',
});

// Enregistrer le plugin Auth0
await fastify.register(fastifyAuth0, {
  domain: process.env.AUTH0_DOMAIN,
  clientId: process.env.AUTH0_CLIENT_ID,
  clientSecret: process.env.AUTH0_CLIENT_SECRET,
  appBaseUrl: process.env.APP_BASE_URL,
  sessionSecret: process.env.SESSION_SECRET,
});

// Route d'accueil - publique
fastify.get('/', async (request, reply) => {
  const session = await fastify.auth0Client.getSession({ request, reply });
  return reply.view('views/home.ejs', {
    isAuthenticated: !!session,
  });
});

// Route de profil - protégée
fastify.get('/profile', {
  preHandler: async (request, reply) => {
    const session = await fastify.auth0Client.getSession({ request, reply });
    if (!session) {
      return reply.redirect('/auth/login');
    }
  }
}, async (request, reply) => {
  const user = await fastify.auth0Client.getUser({ request, reply });
  return reply.view('views/profile.ejs', { user });
});

// Démarrer le serveur
fastify.listen({ port }, (err) => {
  if (err) {
    fastify.log.error(err);
    process.exit(1);
  }
  fastify.log.info(`Server running at http://localhost:${port}`);
});
Points clés :
  • La route d’accueil vérifie le statut d’authentification et le transmet au gabarit
  • La route de profil utilise un preHandler pour la protéger
  • getSession() renvoie la session de l’utilisateur ou null s’il n’est pas authentifié
  • getUser() renvoie les informations du profil de l’utilisateur authentifié
7

Lancez votre application

Démarrez le serveur de développement :
npm run dev
Ouvrez http://localhost:3000 dans votre navigateur.
L’option --watch de Node.js 20+ redémarre automatiquement le serveur lorsque des fichiers sont modifiés.
VérificationVous devriez maintenant avoir 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. Visitez “/profile” - vous voyez les informations de votre profil
  4. Cliquez sur “Logout” - vous êtes déconnecté à la fois de votre application et d’Auth0

Utilisation avancée

Pour appeler des API externes qui nécessitent un jeton d’accès, configurez le SDK avec une audience :
server.js
await fastify.register(fastifyAuth0, {
  domain: process.env.AUTH0_DOMAIN,
  clientId: process.env.AUTH0_CLIENT_ID,
  clientSecret: process.env.AUTH0_CLIENT_SECRET,
  appBaseUrl: process.env.APP_BASE_URL,
  sessionSecret: process.env.SESSION_SECRET,
  audience: process.env.AUTH0_AUDIENCE, // Ajoutez ceci
});
Ajoutez ceci à votre fichier .env :
.env
AUTH0_AUDIENCE=https://your-api.example.com
Ensuite, récupérez et utilisez le jeton d’accès :
server.js
fastify.get('/api-data', {
  preHandler: async (request, reply) => {
    const session = await fastify.auth0Client.getSession({ request, reply });
    if (!session) {
      return reply.redirect('/auth/login');
    }
  }
}, async (request, reply) => {
  try {
    const { accessToken } = await fastify.auth0Client.getAccessToken({ request, reply });

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

    const data = await response.json();
    return data;
  } catch (error) {
    fastify.log.error('API call failed:', error);
    return reply.status(500).send({ error: 'Failed to fetch data' });
  }
});
Par défaut, les routes Auth0 sont montées sous /auth/*. Vous pouvez désactiver le montage automatique et créer des routes personnalisées :
server.js
await fastify.register(fastifyAuth0, {
  domain: process.env.AUTH0_DOMAIN,
  clientId: process.env.AUTH0_CLIENT_ID,
  clientSecret: process.env.AUTH0_CLIENT_SECRET,
  appBaseUrl: process.env.APP_BASE_URL,
  sessionSecret: process.env.SESSION_SECRET,
  mountRoutes: false, // Désactiver le montage automatique
});

// Route de connexion personnalisée
fastify.get('/custom-login', async (request, reply) => {
  const authorizationUrl = await fastify.auth0Client.startInteractiveLogin(
    {
      authorizationParams: {
        redirect_uri: `${process.env.APP_BASE_URL}/custom-callback`
      }
    },
    { request, reply }
  );
  return reply.redirect(authorizationUrl.href);
});

// Route de callback personnalisée
fastify.get('/custom-callback', async (request, reply) => {
  await fastify.auth0Client.completeInteractiveLogin(
    new URL(request.url, process.env.APP_BASE_URL),
    { request, reply }
  );
  return reply.redirect('/');
});

// Route de déconnexion personnalisée
fastify.get('/custom-logout', async (request, reply) => {
  const logoutUrl = await fastify.auth0Client.logout(
    { returnTo: process.env.APP_BASE_URL },
    { request, reply }
  );
  return reply.redirect(logoutUrl.href);
});
N’oubliez pas de mettre à jour vos Allowed Callback URLs dans Auth0 Dashboard pour inclure votre URL de callback personnalisée.
Permettez aux utilisateurs de lier plusieurs fournisseurs d’authentification à un même compte :
server.js
await fastify.register(fastifyAuth0, {
  domain: process.env.AUTH0_DOMAIN,
  clientId: process.env.AUTH0_CLIENT_ID,
  clientSecret: process.env.AUTH0_CLIENT_SECRET,
  appBaseUrl: process.env.APP_BASE_URL,
  sessionSecret: process.env.SESSION_SECRET,
  mountConnectRoutes: true, // Activer les routes de liaison de comptes
});
Cela crée automatiquement les routes suivantes :
  • /auth/connect - Lier un nouveau fournisseur
  • /auth/connect/callback - Gérer le callback de liaison
  • /auth/unconnect - Dissocier un fournisseur
  • /auth/unconnect/callback - Gérer le callback de dissociation
Ajoutez des boutons de liaison à votre page de profil :
views/profile.ejs
<div>
  <a href="/auth/connect?connection=google-oauth2">Lier le compte Google</a>
  <a href="/auth/unconnect?connection=google-oauth2">Dissocier le compte Google</a>
</div>
Convertissez votre projet en TypeScript pour améliorer la sécurité des types :
npm install --save-dev typescript @types/node tsx
Créez un tsconfig.json :
tsconfig.json
{
  "compilerOptions": {
    "target": "ES2022",
    "module": "ESNext",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true,
    "skipLibCheck": true,
    "outDir": "./dist"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}
Renommez server.js en server.ts et ajoutez les types :
server.ts
import 'dotenv/config';
import Fastify, { FastifyRequest, FastifyReply } from 'fastify';
import fastifyView from '@fastify/view';
import fastifyAuth0 from '@auth0/auth0-fastify';
import ejs from 'ejs';

const fastify = Fastify({ logger: true });
const port = process.env.PORT || 3000;

await fastify.register(fastifyView, {
  engine: { ejs },
  root: './views',
});

await fastify.register(fastifyAuth0, {
  domain: process.env.AUTH0_DOMAIN!,
  clientId: process.env.AUTH0_CLIENT_ID!,
  clientSecret: process.env.AUTH0_CLIENT_SECRET!,
  appBaseUrl: process.env.APP_BASE_URL!,
  sessionSecret: process.env.SESSION_SECRET!,
});

fastify.get('/', async (request: FastifyRequest, reply: FastifyReply) => {
  const session = await fastify.auth0Client.getSession({ request, reply });
  return reply.view('views/home.ejs', {
    isAuthenticated: !!session,
  });
});

fastify.listen({ port: Number(port) });
Mettez à jour package.json :
package.json
{
  "scripts": {
    "dev": "tsx watch server.ts",
    "build": "tsc",
    "start": "node dist/server.js"
  }
}

Dépannage

Erreur « Invalid state » après la connexion

Problème : Le state ne correspond pas entre la requête d’authentification et le callback.Solutions :
  1. Assurez-vous que les témoins sont bien définis (et non bloqués par le navigateur)
  2. Vérifiez que l’URL de callback correspond exactement dans Auth0 Dashboard (y compris /auth/callback)
  3. Vérifiez que SESSION_SECRET est défini et contient au moins 64 caractères

Erreur « session is undefined »

Problème : Impossible de récupérer les données de session.Solution : Assurez-vous que le plugin Auth0 est enregistré avant d’accéder aux méthodes de session :
// ✅ Bon ordre
await fastify.register(fastifyAuth0, { ... });
fastify.get('/profile', async (request, reply) => {
  const session = await fastify.auth0Client.getSession({ request, reply });
});

// ❌ Incorrect - await n'est pas utilisé pour le plugin
fastify.register(fastifyAuth0, { ... }); // await manquant
fastify.get('/profile', async (request, reply) => { ... });

Non-correspondance de l’URL de callback

Problème : Erreur « Callback URL mismatch » provenant d’Auth0.Solution :
  1. Accédez à Auth0 Dashboard → Applications → votre application → Settings
  2. Ajoutez http://localhost:3000/auth/callback à Allowed Callback URLs
  3. L’URL doit correspondre exactement (y compris le chemin /auth/callback)

Les variables d’environnement ne se chargent pas

Problème : Les valeurs de configuration sont undefined.Solution :
  1. Assurez-vous que import '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 : afficher les valeurs de configuration (à retirer en production !)
console.log('Config check:', {
  hasDomain: !!process.env.AUTH0_DOMAIN,
  hasClientID: !!process.env.AUTH0_CLIENT_ID,
  hasSecret: !!process.env.SESSION_SECRET,
});

Prochaines étapes

Maintenant que l’authentification fonctionne, pensez à explorer :

Ressources