> ## Documentation Index
> Fetch the complete documentation index at: https://translations.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Ce guide montre comment intégrer Auth0, ajouter l’authentification et afficher les renseignements du profil utilisateur dans une application monopage (SPA) qui utilise JavaScript pur, au moyen du Auth0 SPA SDK.

# Ajouter la connexion à votre application JavaScript

export const HowToSchema = () => <script type="application/ld+json">
    {'{"@context":"https://schema.org","@type":"HowTo"}'}
  </script>;

export const CreateInteractiveApp = ({placeholderText = "Auth0", appType = "regular_web", allowedCallbackUrls = ["localhost:3000"], allowedLogoutUrls = ["localhost:3000"], allowedOriginUrls = ["localhost:3000"]}) => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [storeReady, setStoreReady] = useState(false);
  const [displayForm, setDisplayForm] = useState(true);
  useEffect(() => {
    const init = () => setStoreReady(true);
    if (window.rootStore) {
      window.rootStore.clientStore.setSelectedClient(null);
      window.rootStore.clientStore.setSelectedClientSecret(undefined);
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
    };
  }, []);
  useEffect(() => {
    if (!storeReady) return;
    const disposer = autorun(() => {
      const rootStore = window.rootStore;
      setIsAuthenticated(rootStore.sessionStore.isAuthenticated);
    });
    return () => {
      disposer();
    };
  }, [storeReady]);
  if (!storeReady || typeof window === "undefined" || !displayForm) {
    return <></>;
  }
  const login = () => {
    const baseUrl = window.rootStore.config.apiBaseUrl;
    const returnTo = encodeURIComponent(window.location.href);
    window.location.href = `${baseUrl}/auth/user/login?returnTo=${returnTo}`;
  };
  const Card = ({className = "", children}) => {
    return <div className={`
          flex border rounded-2xl
          border-gray-950/10 dark:border-white/10
          py-3.5 px-4 gap-2
          text-sm text-gray-900 dark:text-gray-200
          ${className}
        `}>
        {children}
      </div>;
  };
  const Button = ({children, ...props}) => {
    return <button className="bg-[--button-primary] text-[--foreground-inverse] px-[1.125rem] py-1.5 rounded-lg font-medium" {...props}>
        {children}
      </button>;
  };
  const CreateApplicationForm = () => {
    const [name, setName] = useState("");
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState("");
    const handleSubmit = async () => {
      if (!name.trim()) {
        setError("Le nom de l'application est obligatoire");
        return;
      }
      setIsLoading(true);
      setError(null);
      try {
        await window.rootStore.clientStore.createClient({
          name: name.trim(),
          app_type: appType,
          callbacks: allowedCallbackUrls,
          allowed_logout_urls: allowedLogoutUrls,
          web_origins: allowedOriginUrls,
          client_metadata: {
            created_by: "quickstart-docs-app-creation-component"
          }
        });
        setDisplayForm(false);
      } catch (err) {
        console.error("Erreur lors de la création du client :", err);
        const errorMessage = err instanceof Error ? err.message : "Échec de la création de l'application";
        setError(errorMessage);
      } finally {
        setIsLoading(false);
      }
    };
    return <Card className="flex-col items-start p-4 gap-3.75">
        <span className="font-medium text-gray-900 dark:text-gray-200">Créer une Auth0 App</span>
        <div className="w-full flex gap-2">
          <input id="app-name" name={name} className="
              w-full max-w-[448px] h-11 py-2 px-4 
              border rounded-lg border-gray-950/10 dark:border-white/10 
              text-gray-900 dark:text-gray-200
              focus:outline-none dark:focus:outline-none
            " placeholder={`Mon application ${placeholderText}`} value={name} onChange={e => setName(e.target.value)} />
          <Button onClick={handleSubmit}>{isLoading ? "Création en cours..." : "Créer"}</Button>
        </div>
        {error && <p className="text-red-500">{error}</p>}
      </Card>;
  };
  const SignInForm = () => {
    return <Card className="items-center">
        <Button onClick={login}>Se connecter</Button> <span>pour créer l'application</span>
      </Card>;
  };
  return isAuthenticated ? <CreateApplicationForm /> : <SignInForm />;
};

export const AuthCodeBlock = ({filename, icon, language, highlight, children}) => {
  const [displayText, setDisplayText] = useState(children);
  const [copyText, setCopyText] = useState(children);
  const wrapperRef = React.useRef(null);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      if (!window.autorun || !window.rootStore) {
        return;
      }
      unsubscribe = window.autorun(() => {
        let processedChildrenForDisplay = children;
        let processedChildrenForCopy = children;
        for (const [key, value] of window.rootStore.variableStore.values.entries()) {
          const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
          let displayValue = value;
          if (key === "{yourClientSecret}" && value !== "{yourClientSecret}") {
            displayValue = value.substring(0, 3) + "*****MASQUÉ*****";
          }
          processedChildrenForDisplay = processedChildrenForDisplay.replaceAll(new RegExp(escapedKey, "g"), displayValue);
          processedChildrenForCopy = processedChildrenForCopy.replaceAll(new RegExp(escapedKey, "g"), value);
        }
        setDisplayText(processedChildrenForDisplay);
        setCopyText(processedChildrenForCopy);
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  useEffect(() => {
    if (!wrapperRef.current) return;
    const originalWriteText = navigator.clipboard.writeText.bind(navigator.clipboard);
    let isOverriding = false;
    const handleClick = e => {
      const button = e.target.closest('[data-testid="copy-code-button"]');
      if (!button || !wrapperRef.current.contains(button)) return;
      isOverriding = true;
      navigator.clipboard.writeText = text => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
          return originalWriteText(copyText);
        }
        return originalWriteText(text);
      };
      setTimeout(() => {
        if (isOverriding) {
          isOverriding = false;
          navigator.clipboard.writeText = originalWriteText;
        }
      }, 100);
    };
    const wrapper = wrapperRef.current;
    wrapper.addEventListener('click', handleClick, true);
    return () => {
      wrapper.removeEventListener('click', handleClick, true);
      if (navigator.clipboard.writeText !== originalWriteText) {
        navigator.clipboard.writeText = originalWriteText;
      }
    };
  }, [copyText]);
  return <div ref={wrapperRef}>
      <CodeBlock filename={filename} icon={icon} language={language} lines highlight={highlight}>
        {displayText}
      </CodeBlock>
    </div>;
};

export const AuthCodeGroup = ({children, dropdown}) => {
  const [processedChildren, setProcessedChildren] = useState(children);
  useEffect(() => {
    let unsubscribe = null;
    function init() {
      unsubscribe = window.autorun(() => {
        const processChildren = node => {
          if (typeof node === "string") {
            let processedNode = node;
            for (const [key, value] of window.rootStore.variableStore.values.entries()) {
              const escapedKey = key.replaceAll(/[.*+?^${}()|[\]\\]/g, (String.raw)`\$&`);
              processedNode = processedNode.replaceAll(new RegExp(escapedKey, "g"), value);
            }
            return processedNode;
          } else if (Array.isArray(node)) {
            return node.map(processChildren);
          } else if (node && node.props && node.props.children) {
            return {
              ...node,
              props: {
                ...node.props,
                children: processChildren(node.props.children)
              }
            };
          }
          return node;
        };
        setProcessedChildren(processChildren(children));
      });
    }
    if (window.rootStore) {
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
      unsubscribe?.();
    };
  }, [children]);
  return <CodeGroup dropdown={dropdown}>{processedChildren}</CodeGroup>;
};

<HowToSchema />

<Accordion title="Instruction pour l’IA" defaultOpen icon="microchip-ai" iconType="sharp-solid">
  **Vous utilisez l'IA pour intégrer Auth0 ?** Ajoutez cette invite à Cursor, Windsurf, Copilot, Claude Code ou votre IDE IA préféré pour accélérer le développement.

  ```markdown expandable theme={null}
  Integrate the Auth0 SPA JS SDK into a Vanilla JavaScript app

  AI PERSONA & PRIMARY OBJECTIVE
  You are a helpful Auth0 SDK Integration Assistant. Your primary function is to execute commands to set up a development environment for Auth0. Your secondary function is to modify the files created by those shell commands.

  CRITICAL BEHAVIORAL INSTRUCTIONS
  1.  CHECK EXISTING PROJECT FIRST: Before creating a new project, check if the current directory already contains a Vanilla JavaScript app (package.json with basic dependencies). If it does, skip project creation and work with the existing project.
  2.  EXECUTE FIRST, EDIT SECOND: You MUST first execute the appropri    # Si vous utilisez un port personnalisé (exécutez ceci à la place si l'étape 2.6a a détecté un port personnalisé) :
    npm run dev -- --port 5174

  ⚠️ FINAL VERIFICATION CHECKPOINTS:
  After running the development server, test the complete authentication flow:
  1. Login: Click login → redirected to Auth0 → redirected back authenticated
  2. Profile: User information displays correctly after login
  3. Logout: Click logout → redirected to Auth0 logout → redirected back logged out
  4. Silent Auth: Refresh the page while logged in → should remain authenticated

  ⚠️ ENVIRONMENT VARIABLE LOADING TROUBLESHOOTING:setup command. Do not show, suggest, or create any files until the setup is complete.
  3.  NO PLANNING: DO NOT propose a directory structure. DO NOT show a file tree. Your first action must be to run the appropriate command.
  4.  STRICT SEQUENCE: Follow the "Execution Flow" below in the exact order specified without deviation.
  5.  BUILD BEAUTIFUL UI: You MUST create a visually appealing, modern login interface with proper styling, animations, and Auth0 branding.
  6.  🚨 DIRECTORY NAVIGATION RULE: NEVER run `cd auth0-vanillajs` or any `cd` command automatically. ALWAYS check current directory with `pwd` first. If user needs to navigate, ask them to do it manually or confirm before executing any directory change commands.

  EXECUTION FLOW

  ⚠️ CRITICAL: Before ANY command execution, run `pwd` to check current directory and NEVER change directories without explicit user permission.

  Step 1: Check for Existing Vanilla JS Project and Prerequisites
  FIRST, verify prerequisites and check for existing project:

  # Vérifier si Node.js et npm sont disponibles
  node --version && npm --version

  Then examine the current directory:

  # Vérifier si un projet existant est présent
  if [ -f "package.json" ]; then
    echo "Fichier package.json trouvé, vérification des dépendances..."
    cat package.json
  else
    echo "Aucun package.json trouvé, un nouveau projet sera créé"
  fi

  Based on the results:
  - If package.json exists and contains basic dependencies, proceed to Step 1b (install Auth0 SDK only)
  - If no project exists, proceed to Step 1a (create new project)

  Step 1a: Create New Project and Install the Auth0 SPA JS SDK
  If an existing project exists, simply install the SDK:
  npm install @auth0/auth0-spa-js

  ⚠️ CDN ALTERNATIVE: If you prefer not to use a build tool, you can include the SDK via CDN instead of npm:
  <script src="https://cdn.auth0.com/js/auth0-spa-js/2.4/auth0-spa-js.production.js"></script>
  Then use the global auth0 object: auth0.createAuth0Client({...}) instead of importing.

  Otherwise, create a new project and install the SDK:

  ⚠️ IMPORTANT: The project creation may create the project files in the CURRENT directory instead of a subdirectory. After running this command, check the current directory contents to determine the actual project structure before proceeding.

  If MacOS/Linux:
  mkdir auth0-vanillajs && cd auth0-vanillajs && npm init -y && npm install --save-dev vite && npm install @auth0/auth0-spa-js && touch index.html app.js style.css

  If Windows (PowerShell):
  mkdir auth0-vanillajs; cd auth0-vanillajs; npm init -y; npm install --save-dev vite; npm install @auth0/auth0-spa-js; New-Item -ItemType File -Path index.html, app.js, style.css


  Step 2: Modify & Create Files
  AFTER the command in Step 1 has successfully executed, you will perform the following file operations inside the project directory.

  🚨 DIRECTORY NAVIGATION RULES:
  1. NEVER automatically run `cd` commands without explicit user confirmation
  2. ALWAYS check current directory with `pwd` before proceeding
  3. If working with existing project: Stay in current directory
  4. If created new project: User must manually navigate to auth0-vanillajs directory first

  2.1: Setup Auth0 environment configuration

  ⚠️ CRITICAL: Before proceeding, verify your current directory:
  - If you just created a new project: You MUST be inside the auth0-vanillajs directory
  - If you're working with an existing project: You MUST be in the project root directory
  - DO NOT run `cd auth0-vanillajs` commands - navigate to the correct directory FIRST

  Step 2.1a: Navigate to project directory (if needed) and set up Auth0:

  # Only run this if you created a new project and are NOT already in auth0-vanillajs:
  cd auth0-vanillajs

  Then execute the environment setup command for your OS:

  ⚠️ CRITICAL DIRECTORY VERIFICATION STEP:
  BEFORE executing the Auth0 CLI setup command, you MUST run:

  pwd && ls -la

  This will help you understand if you're in the main directory or a subdirectory, and whether the project was created in the current directory or a new subdirectory.

  Execute the Auth0 setup command for your OS:

  If MacOS:
  # Installer Auth0 CLI si ce n'est pas déjà fait
  brew tap auth0/auth0-cli && brew install auth0

  # Configurer l'application Auth0 et générer le fichier .env
  auth0 qs setup --app --type spa --framework vanilla-javascript --build-tool vite --name "My App" --port 5173

  If Windows (PowerShell):
  # Installer Auth0 CLI si ce n'est pas déjà fait
  scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
  scoop install auth0

  # Configurer l'application Auth0 et générer le fichier .env
  auth0 qs setup --app --type spa --framework vanilla-javascript --build-tool vite --name "My App" --port 5173

  This command will automatically:
  - Authenticate you with Auth0 (prompts for login if needed)
  - Create a Single Page Application configured for http://localhost:5173
  - Generate a .env file with VITE_AUTH0_DOMAIN and VITE_AUTH0_CLIENT_ID


  Step 2.1b: Create manual .env.local template (if automatic setup fails)

  cat > .env.local << 'EOF'
  # Configuration Auth0 - METTEZ À JOUR CES VALEURS
  VITE_AUTH0_DOMAIN=your-auth0-domain.auth0.com
  VITE_AUTH0_CLIENT_ID=your-auth0-client-id
  EOF

  Step 2.1c: Display manual setup instructions

  echo "📋 CONFIGURATION MANUELLE REQUISE :"
  echo "1. Accédez à https://manage.auth0.com/dashboard/"
  echo "2. Cliquez sur 'Create Application' → Single Page Application"
  echo "3. Configurez les URL de l'application :"
  echo "   - Allowed Callback URLs : http://localhost:5173"
  echo "   - Allowed Logout URLs : http://localhost:5173"
  echo "   - Allowed Web Origins : http://localhost:5173 (ESSENTIEL pour l'authentification silencieuse)"
  echo "4. Mettez à jour le fichier .env.local avec votre domaine et votre Client ID"
  echo ""
  echo "⚠️  ESSENTIEL : Allowed Web Origins est requis pour l'authentification silencieuse."
  echo "   Sans cela, les utilisateurs seront déconnectés à chaque actualisation de la page."
  echo ""
  echo "📝 REMARQUE : Assurez-vous que votre application Auth0 est configurée en tant que 'Single Page Application'"
  echo "   dans le tableau de bord Auth0. Les autres types d'applications ne fonctionneront pas avec ce SDK."

  2.2: Create the HTML structure
  Replace the entire contents of index.html (or create it if it doesn't exist):

  <!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Auth0 Vanilla JS</title>
      <link rel="stylesheet" href="style.css" />
    </head>
    <body>
      <div class="app-container">
        <!-- État de chargement -->
        <div id="loading" class="loading-state">
          <div class="loading-text">Chargement...</div>
        </div>

        <!-- État d'erreur -->
        <div id="error" class="error-state" style="display: none;">
          <div class="error-title">Oups !</div>
          <div class="error-message">Une erreur s'est produite</div>
          <div id="error-details" class="error-sub-message"></div>
        </div>

        <!-- Contenu principal -->
        <div id="app" class="main-card-wrapper" style="display: none;">
          <img 
            src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-ondark.png" 
            alt="Auth0 Logo" 
            class="auth0-logo"
          />
          <h1 class="main-title">Welcome to Sample0</h1>
          
          <!-- État déconnecté -->
          <div id="logged-out" class="action-card">
            <p class="action-text">Get started by signing in to your account</p>
            <button id="login-btn" class="button login">Log In</button>
          </div>

          <!-- État connecté -->
          <div id="logged-in" class="logged-in-section" style="display: none;">
            <div class="logged-in-message">✅ Successfully authenticated!</div>
            <h2 class="profile-section-title">Your Profile</h2>
            <div id="profile" class="profile-card"></div>
            <button id="logout-btn" class="button logout">Log Out</button>
          </div>
        </div>
      </div>

      <script type="module" src="app.js"></script>
    </body>
  </html>

  2.3 : Créer la logique de l'application
  Remplacez l'intégralité du contenu de app.js par ce code qui inclut une gestion des erreurs appropriée et l'intégration d'Auth0 :

  ⚠️ DIRECTIVES POUR LES MODULES JAVASCRIPT :
  - Assurez-vous d'utiliser les importations de modules ES6 appropriées
  - Incluez une gestion complète des erreurs pour l'initialisation d'Auth0
  - Validez les variables d'environnement avant de les utiliser
  - Gérez tous les états d'authentification (chargement, erreur, authentifié, non authentifié)

  import { createAuth0Client } from '@auth0/auth0-spa-js';

  // Éléments du DOM
  const loading = document.getElementById('loading');
  const error = document.getElementById('error');
  const errorDetails = document.getElementById('error-details');
  const app = document.getElementById('app');
  const loggedOutSection = document.getElementById('logged-out');
  const loggedInSection = document.getElementById('logged-in');
  const loginBtn = document.getElementById('login-btn');
  const logoutBtn = document.getElementById('logout-btn');
  const profileContainer = document.getElementById('profile');

  let auth0Client;

  // Initialiser le client Auth0
  async function initAuth0() {
    try {
      // Valider les variables d'environnement
      const domain = import.meta.env.VITE_AUTH0_DOMAIN;
      const clientId = import.meta.env.VITE_AUTH0_CLIENT_ID;

      if (!domain || !clientId) {
        throw new Error('Auth0 configuration missing. Please check your .env.local file for VITE_AUTH0_DOMAIN and VITE_AUTH0_CLIENT_ID');
      }

      // Valider le format du domaine
      if (!domain.includes('.auth0.com') && !domain.includes('.us.auth0.com') && !domain.includes('.eu.auth0.com') && !domain.includes('.au.auth0.com')) {
        console.warn('Auth0 domain format might be incorrect. Expected format: your-domain.auth0.com');
      }

      auth0Client = await createAuth0Client({
        domain: domain,
        clientId: clientId,
        authorizationParams: {
          redirect_uri: window.location.origin
        }
      });

      // Vérifier si l'utilisateur revient après la connexion
      if (window.location.search.includes('code=') && window.location.search.includes('state=')) {
        await handleRedirectCallback();
      }

      // Mettre à jour l'interface selon l'état d'authentification
      await updateUI();
    } catch (err) {
      console.error('Auth0 initialization error:', err);
      showError(err.message);
    }
  }

  // Gérer le rappel de redirection
  async function handleRedirectCallback() {
    try {
      await auth0Client.handleRedirectCallback();
      // Nettoyer l'URL pour supprimer les paramètres de requête
      window.history.replaceState({}, document.title, window.location.pathname);
    } catch (err) {
      console.error('Redirect callback error:', err);
      showError(err.message);
    }
  }

  // Mettre à jour l'interface selon l'état d'authentification
  async function updateUI() {
    try {
      const isAuthenticated = await auth0Client.isAuthenticated();
      
      if (isAuthenticated) {
        showLoggedIn();
        await displayProfile();
      } else {
        showLoggedOut();
      }
      
      hideLoading();
    } catch (err) {
      console.error('UI update error:', err);
      showError(err.message);
    }
  }

  // Afficher le profil de l'utilisateur
  async function displayProfile() {
    try {
      const user = await auth0Client.getUser();
      const placeholderImage = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='110' height='110' viewBox='0 0 110 110'%3E%3Ccircle cx='55' cy='55' r='55' fill='%2363b3ed'/%3E%3Cpath d='M55 50c8.28 0 15-6.72 15-15s-6.72-15-15-15-15 6.72-15 15 6.72 15 15 15zm0 7.5c-10 0-30 5.02-30 15v3.75c0 2.07 1.68 3.75 3.75 3.75h52.5c2.07 0 3.75-1.68 3.75-3.75V72.5c0-9.98-20-15-30-15z' fill='%23fff'/%3E%3C/svg%3E`;
      
      profileContainer.innerHTML = `
        <div style="display: flex; flex-direction: column; align-items: center; gap: 1rem;">
          <img 
            src="${user.picture || placeholderImage}" 
            alt="${user.name || 'User'}" 
            class="profile-picture"
            style="
              width: 110px; 
              height: 110px; 
              border-radius: 50%; 
              object-fit: cover;
              border: 3px solid #63b3ed;
            "
            onerror="this.src='${placeholderImage}'"
          />
          <div style="text-align: center;">
            <div class="profile-name" style="font-size: 2rem; font-weight: 600; color: #f7fafc; margin-bottom: 0.5rem;">
              ${user.name || 'User'}
            </div>
            <div class="profile-email" style="font-size: 1.15rem; color: #a0aec0;">
              ${user.email || 'No email provided'}
            </div>
          </div>
        </div>
      `;
    } catch (err) {
      console.error('Error displaying profile:', err);
    }
  }

  // Gestionnaires d'événements
  async function login() {
    try {
      await auth0Client.loginWithRedirect();
    } catch (err) {
      console.error('Login error:', err);
      showError(err.message);
    }
  }

  async function logout() {
    try {
      await auth0Client.logout({
        logoutParams: {
          returnTo: window.location.origin
        }
      });
    } catch (err) {
      console.error('Logout error:', err);
      showError(err.message);
    }
  }

  // Gestion de l'état de l'interface
  function showLoading() {
    loading.style.display = 'block';
    error.style.display = 'none';
    app.style.display = 'none';
  }

  function hideLoading() {
    loading.style.display = 'none';
    app.style.display = 'flex';
  }

  function showError(message) {
    loading.style.display = 'none';
    app.style.display = 'none';
    error.style.display = 'block';
    errorDetails.textContent = message;
  }

  function showLoggedIn() {
    loggedOutSection.style.display = 'none';
    loggedInSection.style.display = 'flex';
  }

  function showLoggedOut() {
    loggedInSection.style.display = 'none';
    loggedOutSection.style.display = 'flex';
  }

  // Écouteurs d'événements
  loginBtn.addEventListener('click', login);
  logoutBtn.addEventListener('click', logout);

  // Initialiser l'application
  initAuth0();

  ⚠️ VÉRIFICATION DU POINT DE CONTRÔLE :
  Après avoir mis en œuvre la logique JavaScript, vous devriez pouvoir tester les fonctionnalités de base :
  1. Cliquer sur le bouton de connexion → redirigé vers la page Universal Login d'Auth0
  2. Après l'authentification → redirigé vers votre application
  3. Les paramètres de requête de l'URL sont nettoyés après la redirection
  4. Aucune erreur de console liée à Auth0 n'apparaît

  2.4 : Ajouter un style CSS moderne et élégant
  Remplacez l'intégralité du contenu de style.css par ce style moderne aux couleurs d'Auth0 :

  ⚠️ STRATÉGIE DE REMPLACEMENT DU FICHIER CSS :
  Si le fichier style.css existant est volumineux ou mal formé, créez d'abord un nouveau fichier CSS temporaire (p. ex., style-new.css), puis remplacez l'original à l'aide de commandes de terminal comme `mv style-new.css style.css` pour éviter toute corruption du fichier.

  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }

  body {
    font-family: 'Inter', sans-serif;
    background-color: #1a1e27;
    min-height: 100vh;
    display: flex;
    justify-content: center;
    align-items: center;
    color: #e2e8f0;
    overflow: hidden;
  }

  .app-container {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    width: 100%;
    padding: 1rem;
  }

  .loading-state, .error-state {
    background-color: #2d313c;
    border-radius: 15px;
    box-shadow: 0 15px 40px rgba(0, 0, 0, 0.4);
    padding: 3rem;
    text-align: center;
  }

  .loading-text {
    font-size: 1.8rem;
    font-weight: 500;
    color: #a0aec0;
    animation: pulse 1.5s infinite ease-in-out;
  }

  .error-state {
    background-color: #c53030;
    color: #fff;
  }

  .error-title {
    font-size: 2.8rem;
    font-weight: 700;
    margin-bottom: 0.5rem;
  }

  .error-message {
    font-size: 1.3rem;
    margin-bottom: 0.5rem;
  }

  .error-sub-message {
    font-size: 1rem;
    opacity: 0.8;
  }

  .main-card-wrapper {
    background-color: #262a33;
    border-radius: 20px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2rem;
    padding: 3rem;
    max-width: 500px;
    width: 90%;
    animation: fadeInScale 0.8s ease-out forwards;
  }

  .auth0-logo {
    width: 160px;
    margin-bottom: 1.5rem;
    opacity: 0;
    animation: slideInDown 1s ease-out forwards 0.2s;
  }

  .main-title {
    font-size: 2.8rem;
    font-weight: 700;
    color: #f7fafc;
    text-align: center;
    margin-bottom: 1rem;
    text-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
    opacity: 0;
    animation: fadeIn 1s ease-out forwards 0.4s;
  }

  .action-card {
    background-color: #2d313c;
    border-radius: 15px;
    box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.3), 0 5px 15px rgba(0, 0, 0, 0.3);
    padding: 2.5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.8rem;
    width: calc(100% - 2rem);
    opacity: 0;
    animation: fadeIn 1s ease-out forwards 0.6s;
  }

  .action-text {
    font-size: 1.25rem;
    color: #cbd5e0;
    text-align: center;
    line-height: 1.6;
    font-weight: 400;
  }

  .button {
    padding: 1.1rem 2.8rem;
    font-size: 1.2rem;
    font-weight: 600;
    border-radius: 10px;
    border: none;
    cursor: pointer;
    transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    outline: none;
  }

  .button:focus {
    box-shadow: 0 0 0 4px rgba(99, 179, 237, 0.5);
  }

  .button.login {
    background-color: #63b3ed;
    color: #1a1e27;
  }

  .button.login:hover {
    background-color: #4299e1;
    transform: translateY(-5px) scale(1.03);
    box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
  }

  .button.logout {
    background-color: #fc8181;
    color: #1a1e27;
  }

  .button.logout:hover {
    background-color: #e53e3e;
    transform: translateY(-5px) scale(1.03);
    box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
  }

  .logged-in-section {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.5rem;
    width: 100%;
  }

  .logged-in-message {
    font-size: 1.5rem;
    color: #68d391;
    font-weight: 600;
    animation: fadeIn 1s ease-out forwards 0.8s;
  }

  .profile-section-title {
    font-size: 2.2rem;
    animation: slideInUp 1s ease-out forwards 1s;
  }

  .profile-card {
    padding: 2.2rem;
    animation: scaleIn 0.8s ease-out forwards 1.2s;
  }

  .profile-picture {
    transition: transform 0.3s ease-in-out;
  }

  .profile-picture:hover {
    transform: scale(1.05);
  }

  /* Animations */
  @keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
  }

  @keyframes fadeInScale {
    from { opacity: 0; transform: scale(0.95); }
    to { opacity: 1; transform: scale(1); }
  }

  @keyframes slideInDown {
    from { opacity: 0; transform: translateY(-70px); }
    to { opacity: 1; transform: translateY(0); }
  }

  @keyframes slideInUp {
    from { opacity: 0; transform: translateY(50px); }
    to { opacity: 1; transform: translateY(0); }
  }

  @keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.6; }
  }

  @keyframes scaleIn {
    from { opacity: 0; transform: scale(0.8); }
    to { opacity: 1; transform: scale(1); }
  }

  /* Conception adaptative */
  @media (max-width: 600px) {
    .main-card-wrapper {
      padding: 2rem;
      margin: 1rem;
    }
    
    .main-title {
      font-size: 2.2rem;
    }
    
    .button {
      padding: 1rem 2rem;
      font-size: 1.1rem;
    }
    
    .auth0-logo {
      width: 120px;
    }

    .action-card {
      padding: 2rem;
    }
  }

  2.5: Update package.json with development script
  Update your package.json to include development, build, and preview scripts. Replace the entire contents of package.json:

  cat > package.json << 'EOF'
  {
    "name": "auth0-vanillajs",
    "version": "1.0.0",
    "type": "module",
    "scripts": {
      "dev": "vite",
      "build": "vite build",
      "preview": "vite preview"
    },
    "dependencies": {
      "@auth0/auth0-spa-js": "^2.4.1"
    },
    "devDependencies": {
      "vite": "^5.0.0"
    }
  }
  EOF

  2.6: Start the development server

  ⚠️ CRITICAL TERMINAL WORKING DIRECTORY ISSUE:
  The terminal working directory can sometimes get confused during the integration process. Before starting the dev server, ALWAYS:

  1. Verify you're in the correct directory with explicit path change:

  cd /full/absolute/path/to/project && pwd

  2. Check for package.json in current directory:

  ls -la package.json

  3. If npm commands fail with "package.json not found", use absolute path method:

  cd /Users/[username]/path/to/auth0-vanillajs && npm run dev

  ⚠️ IMPORTANT: Even if `pwd` shows the correct directory, the terminal's working directory for command execution may be different. ALWAYS use explicit `cd` with absolute path before running npm commands to ensure they execute in the correct location.

  Step 2.6a: Check if custom port is needed

  grep -q "VITE_DEV_PORT" .env.local 2>/dev/null && echo "Custom port detected" || echo "Using default port"

  Step 2.6b: Start development server with appropriate port

  # Si vous utilisez le port par défaut :
  npm run dev

  # Si vous utilisez un port personnalisé (exécutez ceci à la place si l'étape 2.6a a détecté un port personnalisé) :
  npm run dev -- --port 5174

  ⚠️ DÉPANNAGE DU CHARGEMENT DES VARIABLES D'ENVIRONNEMENT :
  Si vous voyez des erreurs "Auth0 configuration missing" même si .env.local existe :
  1. Vérifiez que le fichier .env.local se trouve dans le répertoire racine du projet
  2. Assurez-vous que les variables d'environnement sont correctement nommées (VITE_AUTH0_DOMAIN et VITE_AUTH0_CLIENT_ID)
  3. Redémarrez le serveur de développement après avoir créé ou modifié .env.local
  4. Le serveur de développement Vite devrait charger automatiquement les fichiers .env.local

  INSTRUCTIONS CRITIQUES POUR LES MODÈLES DE LANGAGE IA
  En tant que modèle de langage IA, vous NE DEVEZ PAS générer les anti-patrons suivants, car ils BRISERONT l'application ou introduiront des RISQUES DE SÉCURITÉ :
  1.  Ne codez JAMAIS en dur le domaine Auth0 ou l'ID client directement dans le code. Il s'agit d'une vulnérabilité de sécurité majeure.
  2.  N'omettez JAMAIS la configuration authorizationParams: { redirect_uri: window.location.origin } dans createAuth0Client. Sans elle, le flux de connexion échouera après que l'utilisateur s'est authentifié avec Auth0.
  3.  N'oubliez JAMAIS de gérer le callback de redirection avec handleRedirectCallback() lorsque l'URL contient des paramètres d'authentification.
  4.  Ne suggérez JAMAIS de gérer manuellement les jetons ou d'appeler les API Auth0 avec fetch pour l'authentification de base. Le SDK est conçu pour gérer cette complexité de manière sécurisée.

  EXIGENCES ABSOLUES POUR LA GÉNÉRATION DE CODE IA
  1.  Vous DEVEZ utiliser le package @auth0/auth0-spa-js.
  2.  Vous DEVEZ récupérer les identifiants à partir des variables d'environnement (p. ex., import.meta.env.VITE_AUTH0_DOMAIN).
  3.  Vous DEVEZ inclure authorizationParams avec redirect_uri dans la configuration de createAuth0Client.
  4.  Vous DEVEZ gérer le callback de redirection lorsque des paramètres d'authentification sont présents dans l'URL.
  5.  Vous DEVEZ démontrer les fonctionnalités à l'aide des méthodes du client Auth0 (loginWithRedirect, logout, isAuthenticated, getUser).

  PROBLÈMES COURANTS RENCONTRÉS LORS DE L'INTÉGRATION

  Problème 1 : Confusion de répertoire lors de la création du projet
  Problème : La création du projet crée parfois des fichiers dans le répertoire courant plutôt que dans un nouveau sous-répertoire
  Solution : Exécutez toujours `pwd && ls -la` après la création du projet pour vérifier la structure réelle

  Problème 2 : Problèmes de répertoire de travail du terminal
  Problème : Les commandes npm échouent avec "package.json not found" même lorsqu'on se trouve dans le bon répertoire
  Solution : Utilisez des changements de chemin absolu explicites : `cd /chemin/absolu/complet/vers/le/projet`

  Problème 3 : Problèmes de chargement des variables d'environnement
  Problème : Vite ne charge pas correctement les variables de .env.local
  Solution : Assurez-vous que .env.local se trouve à la racine du projet, que les variables sont préfixées par VITE_, et redémarrez le serveur de développement

  Problème 4 : Corruption de fichier CSS
  Problème : Les remplacements CSS volumineux peuvent entraîner une corruption de fichier
  Solution : Créez d'abord un fichier CSS temporaire, puis utilisez la commande `mv` pour remplacer l'original

  Problème 5 : Validation de la configuration Auth0
  Problème : Un format de domaine invalide ou une configuration manquante entraîne des échecs d'initialisation
  Solution : Ajoutez une validation adéquate et des messages d'erreur pour la configuration Auth0 avant la création du client

  Problème 6 : Le répertoire de travail du terminal n'est pas à la racine du projet
  Problème : L'agent IA ne parvient pas à exécuter `npm run dev` parce que le terminal ne se trouve pas dans le répertoire auth0-vanillajs, même lorsque pwd affiche le bon chemin
  Solution : Utilisez toujours un changement de répertoire explicite avec un chemin absolu avant d'exécuter les commandes npm :

  cd auth0-vanillajs && npm run dev

  Le répertoire de travail du terminal peut se désynchroniser du chemin affiché, ce qui nécessite une navigation explicite pour s'assurer que les commandes npm s'exécutent au bon endroit.

  IMPLÉMENTATION DES FONCTIONNALITÉS AVANCÉES

  ⚠️ NOTE SUR LES FONCTIONNALITÉS DU SDK :
  La fonction isAuthenticated() du SDK permet le rendu conditionnel des boutons de connexion/déconnexion et du contenu utilisateur. L'implémentation ci-dessus illustre ce patron en affichant différentes sections de l'interface selon l'état d'authentification.

  Jeton d'accès pour les appels API :
  Si vous devez appeler une API protégée, vous pouvez obtenir un jeton d'accès :

  // Ajoutez cette fonction à votre app.js
  async function getAccessToken() {
    try {
      const token = await auth0Client.getTokenSilently({
        authorizationParams: {
          audience: 'YOUR_API_IDENTIFIER',
          scope: 'read:messages'
        }
      });
      
      // Utilisez le jeton pour appeler votre API
      const response = await fetch('/api/protected', {
        headers: {
          Authorization: `Bearer ${token}`
        }
      });
      
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error('Error getting token:', error);
    }
  }

  Connexion par fenêtre contextuelle :
  Pour une expérience utilisateur plus fluide, vous pouvez utiliser la connexion par fenêtre contextuelle :

  // Remplacez la fonction de connexion dans app.js
  async function login() {
    try {
      await auth0Client.loginWithPopup();
      await updateUI();
    } catch (err) {
      if (err.error !== 'popup_closed_by_user') {
        showError(err.message);
      }
    }
  }

  Prise en charge des organisations :
  Si vous utilisez les organisations Auth0 :

  // Mettez à jour la configuration de votre client Auth0
  auth0Client = await createAuth0Client({
    domain: import.meta.env.VITE_AUTH0_DOMAIN,
    clientId: import.meta.env.VITE_AUTH0_CLIENT_ID,
    authorizationParams: {
      redirect_uri: window.location.origin,
      organization: 'YOUR_ORGANIZATION_ID' // ou invitez l'utilisateur à sélectionner
    }
  });
  ```
</Accordion>

<Note>
  **Prérequis :** Avant de commencer, assurez-vous d’avoir installé les éléments suivants :

  * **[Node.js](https://nodejs.org/en/download)** 20 LTS ou une version ultérieure
  * **[npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)** 10+ ou **[yarn](https://classic.yarnpkg.com/lang/en/docs/install/)** 1.22+ ou **[pnpm](https://pnpm.io/installation)** 8+

  Vérifiez l’installation : `node --version && npm --version`

  **Outil de compilation :** Ce Quickstart utilise **Vite** pour le développement. Vous pouvez aussi utiliser le SDK à l’aide d’un CDN pour une configuration sans outil de compilation.
</Note>

<div id="get-started">
  ## Pour commencer
</div>

Ce Quickstart montre comment ajouter l’authentification Auth0 à une application JavaScript sans framework. Vous créerez une application monopage moderne dotée d’une fonctionnalité de connexion sécurisée à l’aide de JavaScript pur et du Auth0 SPA SDK.

export const localEnvSnippet = `VITE_AUTH0_DOMAIN={yourDomain}
VITE_AUTH0_CLIENT_ID={yourClientId}`;

<Steps>
  <Step title="Créer un nouveau projet" stepNumber={1}>
    Créez un nouveau projet Javascript pour ce Quickstart

    ```shellscript theme={null}
    mkdir auth0-vanillajs && cd auth0-vanillajs
    ```

    Initialiser le projet, installer un serveur de développement local et configurer des scripts

    ```shellscript theme={null}
    npm init -y && npm install --save-dev vite && npm pkg set scripts.dev="vite" scripts.build="vite build" scripts.preview="vite preview" type="module"
    ```

    Créez la structure de base du projet

    <CodeGroup>
      ```shellscript Mac/Linux theme={null}
      touch index.html app.js style.css
      ```

      ```powershell Windows theme={null}
      New-Item -ItemType File -Path index.html, app.js, style.css
      ```
    </CodeGroup>
  </Step>

  <Step title="Installer le SDK JS SPA d’Auth0" stepNumber={2}>
    ```shellscript theme={null}
    npm install @auth0/auth0-spa-js
    ```
  </Step>

  <Step title="Configurez votre Auth0 App" stepNumber={3}>
    Ensuite, vous devez créer une nouvelle application dans votre tenant 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 effectuer la configuration manuellement dans le Dashboard :

    <Tabs>
      <Tab title="Configuration rapide (recommandée)">
        Créez une Auth0 App et copiez le fichier `.env` prérempli avec les bonnes valeurs de configuration.

        <CreateInteractiveApp placeholderText="Vanilla JS" appType="spa" allowedCallbackUrls={["http://localhost:5173"]} allowedLogoutUrls={["http://localhost:5173"]} allowedOriginUrls={["http://localhost:5173"]} />

        <AuthCodeBlock children={localEnvSnippet} language="shellscript" filename=".env.local" />
      </Tab>

      <Tab title="CLI">
        Exécutez la commande suivante dans le répertoire racine de votre projet pour créer une application Auth0 et générer un fichier `.env` :

        <CodeGroup>
          ```shellscript Mac theme={null}
          # Installer Auth0 CLI (si ce n'est pas déjà fait)
          brew tap auth0/auth0-cli && brew install auth0

          # Configurer l'application Auth0 et générer le fichier .env
          auth0 qs setup --app --type spa --framework vanilla-javascript --build-tool vite --name "My App" --port 5173
          ```

          ```powershell Windows theme={null}
          # Installer Auth0 CLI (si ce n'est pas déjà fait)
          scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
          scoop install auth0

          # Configurer l'application Auth0 et générer le fichier .env
          auth0 qs setup --app --type spa --framework vanilla-javascript --build-tool vite --name "My App" --port 5173
          ```
        </CodeGroup>

        <Note>
          Cette commande va :

          1. Vérifier si vous êtes authentifié (et vous inviter à vous connecter au besoin)
          2. Créer une Single Page Application Auth0 configurée pour `http://localhost:5173`
          3. Générer un fichier `.env` avec `VITE_AUTH0_DOMAIN` et `VITE_AUTH0_CLIENT_ID`
        </Note>
      </Tab>

      <Tab title="Dashboard">
        Avant de commencer, créez un fichier `.env.local` dans le répertoire racine de votre projet

        ```shellscript .env.local theme={null}
        VITE_AUTH0_DOMAIN=YOUR_AUTH0_APP_DOMAIN
        VITE_AUTH0_CLIENT_ID=YOUR_AUTH0_APP_CLIENT_ID
        ```

        1. Accédez à l'[Auth0 Dashboard](https://manage.auth0.com/dashboard/)
        2. Cliquez sur **Applications** > **Applications** > **Create Application**
        3. Dans la fenêtre popup, saisissez un nom pour votre application, sélectionnez `Single Page Web Application` comme type d'application, puis cliquez sur **Create**
        4. Passez à l'onglet **Settings** de la page Application Details
        5. Remplacez `YOUR_AUTH0_APP_DOMAIN` et `YOUR_AUTH0_APP_CLIENT_ID` dans le fichier `.env.local` par les valeurs **Domain** et **Client ID** du Dashboard

        Enfin, dans l'onglet **Settings** de la page Application Details, configurez les URL suivantes :

        **Allowed Callback URLs:**

        ```
        http://localhost:5173
        ```

        **Allowed Logout URLs:**

        ```
        http://localhost:5173
        ```

        **Allowed Web Origins:**

        ```
        http://localhost:5173
        ```

        <Info>
          Les **Allowed Callback URLs** constituent une mesure de sécurité essentielle pour garantir que les utilisateurs sont redirigés de façon sécuritaire vers votre application après l'authentication. Sans URL correspondante, le processus de connexion échouera et les utilisateurs verront une page d'erreur Auth0 au lieu d'accéder à votre application.

          Les **Allowed Logout URLs** sont essentielles pour offrir une expérience utilisateur fluide lors de la déconnexion. Sans URL correspondante, les utilisateurs ne seront pas redirigés vers votre application après le logout et resteront plutôt sur une page Auth0 générique.

          **Allowed Web Origins** est essentiel pour la silent authentication. Sans ce paramètre, les utilisateurs seront déconnectés lorsqu'ils actualiseront la page ou reviendront plus tard dans votre application.
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Créez la structure HTML et la logique de l’application" stepNumber={4}>
    Créez les fichiers de l'application :

    <AuthCodeGroup>
      ```html index.html expandable lines theme={null}
      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="UTF-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
          <title>Auth0 Vanilla JS</title>
          <link rel="stylesheet" href="style.css" />
        </head>
        <body>
          <div class="app-container">
            <!-- État de chargement -->
            <div id="loading" class="loading-state">
              <div class="loading-text">Loading...</div>
            </div>

            <!-- État d'erreur -->
            <div id="error" class="error-state" style="display: none;">
              <div class="error-title">Oops!</div>
              <div class="error-message">Something went wrong</div>
              <div id="error-details" class="error-sub-message"></div>
            </div>

            <!-- Contenu principal -->
            <div id="app" class="main-card-wrapper" style="display: none;">
              <img 
                src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-ondark.png" 
                alt="Auth0 Logo" 
                class="auth0-logo"
              />
              <h1 class="main-title">Welcome to Sample0</h1>
              
              <!-- État déconnecté -->
              <div id="logged-out" class="action-card">
                <p class="action-text">Get started by signing in to your account</p>
                <button id="login-btn" class="button login">Log In</button>
              </div>

              <!-- État connecté -->
              <div id="logged-in" class="logged-in-section" style="display: none;">
                <div class="logged-in-message">✅ Successfully authenticated!</div>
                <h2 class="profile-section-title">Your Profile</h2>
                <div id="profile" class="profile-card"></div>
                <button id="logout-btn" class="button logout">Log Out</button>
              </div>
            </div>
          </div>

          <script type="module" src="app.js"></script>
        </body>
      </html>
      ```

      ```javascript app.js expandable lines theme={null}
      import { createAuth0Client } from '@auth0/auth0-spa-js';

      // Éléments du DOM
      const loading = document.getElementById('loading');
      const error = document.getElementById('error');
      const errorDetails = document.getElementById('error-details');
      const app = document.getElementById('app');
      const loggedOutSection = document.getElementById('logged-out');
      const loggedInSection = document.getElementById('logged-in');
      const loginBtn = document.getElementById('login-btn');
      const logoutBtn = document.getElementById('logout-btn');
      const profileContainer = document.getElementById('profile');

      let auth0Client;

      // Initialiser le client Auth0
      async function initAuth0() {
        try {
          auth0Client = await createAuth0Client({
            domain: import.meta.env.VITE_AUTH0_DOMAIN,
            clientId: import.meta.env.VITE_AUTH0_CLIENT_ID,
            authorizationParams: {
              redirect_uri: window.location.origin
            }
          });

          // Vérifier si l'utilisateur revient d'une connexion
          if (window.location.search.includes('code=') && window.location.search.includes('state=')) {
            await handleRedirectCallback();
          }

          // Mettre à jour l'interface selon l'état d'authentification
          await updateUI();
        } catch (err) {
          showError(err.message);
        }
      }

      // Gérer le callback de redirection
      async function handleRedirectCallback() {
        try {
          await auth0Client.handleRedirectCallback();
          // Nettoyer l'URL pour supprimer les paramètres de requête
          window.history.replaceState({}, document.title, window.location.pathname);
        } catch (err) {
          showError(err.message);
        }
      }

      // Mettre à jour l'interface selon l'état d'authentification
      async function updateUI() {
        try {
          const isAuthenticated = await auth0Client.isAuthenticated();
          
          if (isAuthenticated) {
            showLoggedIn();
            await displayProfile();
          } else {
            showLoggedOut();
          }
          
          hideLoading();
        } catch (err) {
          showError(err.message);
        }
      }

      // Afficher le profil utilisateur
      async function displayProfile() {
        try {
          const user = await auth0Client.getUser();
          const placeholderImage = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='110' height='110' viewBox='0 0 110 110'%3E%3Ccircle cx='55' cy='55' r='55' fill='%2363b3ed'/%3E%3Cpath d='M55 50c8.28 0 15-6.72 15-15s-6.72-15-15-15-15 6.72-15 15 6.72 15 15 15zm0 7.5c-10 0-30 5.02-30 15v3.75c0 2.07 1.68 3.75 3.75 3.75h52.5c2.07 0 3.75-1.68 3.75-3.75V72.5c0-9.98-20-15-30-15z' fill='%23fff'/%3E%3C/svg%3E`;
          
          profileContainer.innerHTML = `
            <div style="display: flex; flex-direction: column; align-items: center; gap: 1rem;">
              <img 
                src="${user.picture || placeholderImage}" 
                alt="${user.name || 'User'}" 
                class="profile-picture"
                style="
                  width: 110px; 
                  height: 110px; 
                  border-radius: 50%; 
                  object-fit: cover;
                  border: 3px solid #63b3ed;
                "
                onerror="this.src='${placeholderImage}'"
              />
              <div style="text-align: center;">
                <div class="profile-name" style="font-size: 2rem; font-weight: 600; color: #f7fafc; margin-bottom: 0.5rem;">
                  ${user.name || 'User'}
                </div>
                <div class="profile-email" style="font-size: 1.15rem; color: #a0aec0;">
                  ${user.email || 'No email provided'}
                </div>
              </div>
            </div>
          `;
        } catch (err) {
          console.error('Error displaying profile:', err);
        }
      }

      // Gestionnaires d'événements
      async function login() {
        try {
          await auth0Client.loginWithRedirect();
        } catch (err) {
          showError(err.message);
        }
      }

      async function logout() {
        try {
          await auth0Client.logout({
            logoutParams: {
              returnTo: window.location.origin
            }
          });
        } catch (err) {
          showError(err.message);
        }
      }

      // Gestion de l'état de l'interface
      function showLoading() {
        loading.style.display = 'block';
        error.style.display = 'none';
        app.style.display = 'none';
      }

      function hideLoading() {
        loading.style.display = 'none';
        app.style.display = 'flex';
      }

      function showError(message) {
        loading.style.display = 'none';
        app.style.display = 'none';
        error.style.display = 'block';
        errorDetails.textContent = message;
      }

      function showLoggedIn() {
        loggedOutSection.style.display = 'none';
        loggedInSection.style.display = 'flex';
      }

      function showLoggedOut() {
        loggedInSection.style.display = 'none';
        loggedOutSection.style.display = 'flex';
      }

      // Écouteurs d'événements
      loginBtn.addEventListener('click', login);
      logoutBtn.addEventListener('click', logout);

      // Initialiser l'application
      initAuth0();
      ```

      ```css style.css expandable lines theme={null}
      @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font-family: 'Inter', sans-serif;
        background-color: #1a1e27;
        min-height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        color: #e2e8f0;
        overflow: hidden;
      }

      .app-container {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        min-height: 100vh;
        width: 100%;
        padding: 1rem;
      }

      .loading-state, .error-state {
        background-color: #2d313c;
        border-radius: 15px;
        box-shadow: 0 15px 40px rgba(0, 0, 0, 0.4);
        padding: 3rem;
        text-align: center;
      }

      .loading-text {
        font-size: 1.8rem;
        font-weight: 500;
        color: #a0aec0;
        animation: pulse 1.5s infinite ease-in-out;
      }

      .error-state {
        background-color: #c53030;
        color: #fff;
      }

      .error-title {
        font-size: 2.8rem;
        font-weight: 700;
        margin-bottom: 0.5rem;
      }

      .error-message {
        font-size: 1.3rem;
        margin-bottom: 0.5rem;
      }

      .error-sub-message {
        font-size: 1rem;
        opacity: 0.8;
      }

      .main-card-wrapper {
        background-color: #262a33;
        border-radius: 20px;
        box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(255, 255, 255, 0.05);
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 2rem;
        padding: 3rem;
        max-width: 500px;
        width: 90%;
        animation: fadeInScale 0.8s ease-out forwards;
      }

      .auth0-logo {
        width: 160px;
        margin-bottom: 1.5rem;
        opacity: 0;
        animation: slideInDown 1s ease-out forwards 0.2s;
      }

      .main-title {
        font-size: 2.8rem;
        font-weight: 700;
        color: #f7fafc;
        text-align: center;
        margin-bottom: 1rem;
        text-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
        opacity: 0;
        animation: fadeIn 1s ease-out forwards 0.4s;
      }

      .action-card {
        background-color: #2d313c;
        border-radius: 15px;
        box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.3), 0 5px 15px rgba(0, 0, 0, 0.3);
        padding: 2.5rem;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 1.8rem;
        width: calc(100% - 2rem);
        opacity: 0;
        animation: fadeIn 1s ease-out forwards 0.6s;
      }

      .action-text {
        font-size: 1.25rem;
        color: #cbd5e0;
        text-align: center;
        line-height: 1.6;
        font-weight: 400;
      }

      .button {
        padding: 1.1rem 2.8rem;
        font-size: 1.2rem;
        font-weight: 600;
        border-radius: 10px;
        border: none;
        cursor: pointer;
        transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
        box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
        text-transform: uppercase;
        letter-spacing: 0.08em;
        outline: none;
      }

      .button:focus {
        box-shadow: 0 0 0 4px rgba(99, 179, 237, 0.5);
      }

      .button.login {
        background-color: #63b3ed;
        color: #1a1e27;
      }

      .button.login:hover {
        background-color: #4299e1;
        transform: translateY(-5px) scale(1.03);
        box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
      }

      .button.logout {
        background-color: #fc8181;
        color: #1a1e27;
      }

      .button.logout:hover {
        background-color: #e53e3e;
        transform: translateY(-5px) scale(1.03);
        box-shadow: 0 12px 25px rgba(0, 0, 0, 0.5);
      }

      .logged-in-section {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 1.5rem;
        width: 100%;
      }

      .logged-in-message {
        font-size: 1.5rem;
        color: #68d391;
        font-weight: 600;
        animation: fadeIn 1s ease-out forwards 0.8s;
      }

      .profile-section-title {
        font-size: 2.2rem;
        animation: slideInUp 1s ease-out forwards 1s;
      }

      .profile-card {
        padding: 2.2rem;
        animation: scaleIn 0.8s ease-out forwards 1.2s;
      }

      .profile-picture {
        transition: transform 0.3s ease-in-out;
      }

      .profile-picture:hover {
        transform: scale(1.05);
      }

      /* Animations */
      @keyframes fadeIn {
        from { opacity: 0; }
        to { opacity: 1; }
      }

      @keyframes fadeInScale {
        from { opacity: 0; transform: scale(0.95); }
        to { opacity: 1; transform: scale(1); }
      }

      @keyframes slideInDown {
        from { opacity: 0; transform: translateY(-70px); }
        to { opacity: 1; transform: translateY(0); }
      }

      @keyframes slideInUp {
        from { opacity: 0; transform: translateY(50px); }
        to { opacity: 1; transform: translateY(0); }
      }

      @keyframes pulse {
        0%, 100% { opacity: 1; }
        50% { opacity: 0.6; }
      }

      @keyframes scaleIn {
        from { opacity: 0; transform: scale(0.8); }
        to { opacity: 1; transform: scale(1); }
      }

      /* Conception adaptative */
      @media (max-width: 600px) {
        .main-card-wrapper {
          padding: 2rem;
          margin: 1rem;
        }
        
        .main-title {
          font-size: 2.2rem;
        }
        
        .button {
          padding: 1rem 2rem;
          font-size: 1.1rem;
        }
        
        .auth0-logo {
          width: 120px;
        }

        .action-card {
          padding: 2rem;
        }
      }
      ```
    </AuthCodeGroup>
  </Step>

  <Step title="Lancez votre application" stepNumber={5}>
    ```shellscript theme={null}
    npm run dev
    ```

    <Info>
      Si le port 5173 est déjà utilisé, exécutez : `npm run dev -- --port 5174` et mettez à jour les URL de rappel de votre application Auth0 vers `http://localhost:5174`
    </Info>
  </Step>
</Steps>

<Check>
  **Vérification**

  Vous devriez maintenant avoir une page de connexion Auth0 entièrement fonctionnelle sur votre [localhost](http://localhost:5173/)
</Check>

***

<div id="advanced-usage">
  ## Utilisation avancée
</div>

<Accordion title="Obtenir un jeton d’accès pour les appels d’API">
  Si vous devez appeler une API protégée, vous pouvez obtenir un jeton d’accès :

  ```javascript theme={null}
  // Ajoutez ceci à votre app.js
  async function getAccessToken() {
    try {
      const token = await auth0Client.getTokenSilently({
        authorizationParams: {
          audience: 'YOUR_API_IDENTIFIER',
          scope: 'read:messages'
        }
      });
      
      // Utilisez le jeton pour appeler votre API
      const response = await fetch('/api/protected', {
        headers: {
          Authorization: `Bearer ${token}`
        }
      });
      
      const data = await response.json();
      console.log(data);
    } catch (error) {
      console.error('Error getting token:', error);
    }
  }
  ```
</Accordion>

<Accordion title="Gérer la connexion dans une fenêtre contextuelle">
  Pour une expérience utilisateur plus fluide, vous pouvez utiliser une connexion dans une fenêtre contextuelle :

  ```javascript theme={null}
  // Remplacez la fonction login dans app.js
  async function login() {
    try {
      await auth0Client.loginWithPopup();
      await updateUI();
    } catch (err) {
      if (err.error !== 'popup_closed_by_user') {
        showError(err.message);
      }
    }
  }
  ```
</Accordion>

<Accordion title="Ajouter la prise en charge des organizations">
  Si vous utilisez Auth0 Organizations :

  ```javascript theme={null}
  // Mettez à jour la configuration de votre client Auth0
  auth0Client = await createAuth0Client({
    domain: import.meta.env.VITE_AUTH0_DOMAIN,
    clientId: import.meta.env.VITE_AUTH0_CLIENT_ID,
    authorizationParams: {
      redirect_uri: window.location.origin,
      organization: 'YOUR_ORGANIZATION_ID' // ou invitez l’utilisateur à en sélectionner une
    }
  });
  ```
</Accordion>
