> ## 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 de l’utilisateur dans une application monopage (SPA) qui utilise Svelte, à l’aide du SDK Auth0 SPA JS.

# Ajouter la connexion à votre application Svelte

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 requis");
        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 de l'application :", 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 application Auth0</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) + "*****MASKED*****";
          }
          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 />

<Callout icon="pencil" color="#FFC107" iconType="solid">
  Ce guide de démarrage rapide est actuellement en **bêta**. N’hésitez pas à nous faire part de vos commentaires!
</Callout>

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

  ```markdown expandable theme={null}
  Integrate the Auth0 SPA JS SDK into a Svelte 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 with Svelte. 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 Svelte app (package.json with Svelte dependencies). If it does, skip project creation and work with the existing project.
  2. EXECUTE FIRST, EDIT SECOND: You MUST first execute the appropriate 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.

  EXECUTION FLOW

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

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

  Then examine the current directory:

    # Vérifier l'existence d'un projet Svelte
    if [ -f "package.json" ]; then
      echo "Found package.json, checking for Svelte dependencies..."
      cat package.json
    else
      echo "No package.json found, will create new project"
    fi

  Based on the results:
  - If package.json exists and contains Svelte dependencies, proceed to Step 1b (install Auth0 SDK only)
  - If no Svelte 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
  Otherwise, create a new project and install the SDK:

  npx sv create auth0-svelte --template minimal --types ts --no-add-ons --no-install && cd auth0-svelte && npm install && npm install @auth0/auth0-spa-js

  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.

  2.1: Setup Auth0 environment configuration

  Execute the environment setup command for your OS:

  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 svelte --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 svelte --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

  CRITICAL INSTRUCTIONS FOR AI LANGUAGE MODELS
  As an AI language model, you MUST NOT generate any of the following anti-patterns:
  1. NEVER hardcode the Auth0 Domain or Client ID directly in the code. This is a major security vulnerability.
  2. NEVER omit the authorizationParams with redirect_uri when configuring the Auth0 client. Without it, the login flow will fail.
  3. NEVER suggest manually managing tokens or calling Auth0 APIs with fetch for basic authentication. The SDK is designed to handle this complexity securely.

  ABSOLUTE REQUIREMENTS FOR AI CODE GENERATION
  1. You MUST use the @auth0/auth0-spa-js package.
  2. You MUST retrieve credentials from environment variables (e.g., import.meta.env.VITE_AUTH0_DOMAIN).
  3. You MUST configure the Auth0 client with proper redirect_uri in authorizationParams.
  4. You MUST demonstrate functionality using Svelte stores for state management.
  ```
</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+

  **Compatibilité des versions de Svelte :** Ce guide de démarrage rapide fonctionne avec **Svelte 5.x** et les versions ultérieures.
</Note>

<div id="get-started">
  ## Premiers pas
</div>

Ce guide de démarrage rapide explique comment ajouter l’authentification Auth0 à une application Svelte. Vous créerez une application monopage sécurisée avec des fonctions de connexion, de déconnexion et de profil d’utilisateur à l’aide du SDK Auth0 SPA JS.

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 Svelte pour ce guide de démarrage rapide

    ```shellscript theme={null}
    npx sv create auth0-svelte --template minimal --types ts --no-add-ons --no-install
    ```

    Ouvrez le projet

    ```shellscript theme={null}
    cd auth0-svelte
    ```
  </Step>

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

  <Step title="Configurez votre application Auth0" stepNumber={3}>
    La prochaine étape consiste à créer une nouvelle application sur votre locataire Auth0 et à ajouter les variables d'environnement à votre projet.

    Vous avez trois options pour configurer votre application Auth0 : utiliser l'outil Quick Setup (recommandé), exécuter une commande CLI ou faire la configuration manuellement dans l'Auth0 Dashboard :

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

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

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

      <Tab title="CLI">
        Exécutez la commande suivante à la 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 svelte --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 svelte --build-tool vite --name "My App" --port 5173
          ```
        </CodeGroup>

        <Note>
          Cette commande permet de :

          1. Vérifier si vous êtes authentifié(e) (et vous inviter à vous connecter au besoin)
          2. Créer une application Web monopage 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` à la racine de votre projet

        ```shellscript .env 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 contextuelle, saisissez un nom pour votre application, sélectionnez `Single Page Web Application` comme type d'application, puis cliquez sur **Create**
        4. Ouvrez l'onglet **Settings** sur la page Application Details
        5. Remplacez `YOUR_AUTH0_APP_DOMAIN` et `YOUR_AUTH0_APP_CLIENT_ID` dans le fichier `.env` par les valeurs **Domaine** et **ID client** du dashboard

        Enfin, dans l'onglet **Settings** de votre 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>
          **Allowed Callback URLs** constituent une mesure de sécurité essentielle pour garantir que les utilisateurs sont redirigés en toute sécurité vers votre application après l'authentification. Sans URL correspondante, le processus de connexion échouera et les utilisateurs verront une page d'erreur Auth0 au lieu d'accéder à votre application.

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

          **Allowed Web Origins** est essentiel pour l'authentification silencieuse. Sans cette configuration, les utilisateurs seront déconnectés lorsqu'ils actualiseront la page ou reviendront plus tard à votre application.
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Créer le store Auth0" stepNumber={4}>
    Créez le fichier du store

    <CodeGroup>
      ```shellscript Mac/Linux theme={null}
      mkdir -p src/lib/stores && touch src/lib/stores/auth.ts
      ```

      ```powershell Windows theme={null}
      New-Item -ItemType Directory -Force -Path src/lib/stores
      New-Item -ItemType File -Path src/lib/stores/auth.ts
      ```
    </CodeGroup>

    Ajoutez le code suivant pour gérer l’état de l’authentification

    ```typescript src/lib/stores/auth.ts lines expandable theme={null}
      import { writable, derived, get, type Readable } from 'svelte/store';
      import { createAuth0Client, type Auth0Client, type User } from '@auth0/auth0-spa-js';
      import { browser } from '$app/environment';

      export const auth0Client = writable<Auth0Client | null>(null);
      export const user = writable<User | null>(null);
      export const isAuthenticated = writable<boolean>(false);
      export const isLoading = writable<boolean>(true);
      export const error = writable<string | null>(null);

      // Stores dérivés
      export const isLoggedIn: Readable<boolean> = derived(
        [isAuthenticated, isLoading],
        ([$isAuthenticated, $isLoading]) => $isAuthenticated && !$isLoading
      );

      export async function initializeAuth() {
        if (!browser) return;
        
        try {
          const client = await createAuth0Client({
            domain: import.meta.env.VITE_AUTH0_DOMAIN,
            clientId: import.meta.env.VITE_AUTH0_CLIENT_ID,
            authorizationParams: {
              redirect_uri: window.location.origin
            },
            useRefreshTokens: true,
            cacheLocation: 'localstorage'
          });

          auth0Client.set(client);

          // Traiter le rappel
          if (window.location.search.includes('code=')) {
            await client.handleRedirectCallback();
            window.history.replaceState({}, document.title, window.location.pathname);
          }

          // Vérifier l'état d'authentification
          const authenticated = await client.isAuthenticated();
          isAuthenticated.set(authenticated);

          if (authenticated) {
            const userData = await client.getUser();
            user.set(userData || null);
          }

          error.set(null);
        } catch (err) {
          console.error('Erreur d\'initialisation de l\'authentification :', err);
          error.set(err instanceof Error ? err.message : 'Authentication initialization failed');
        } finally {
          isLoading.set(false);
        }
      }

      export async function login() {
        const client = get(auth0Client);
        if (client) {
          await client.loginWithRedirect();
        }
      }

      export async function logout() {
        const client = get(auth0Client);
        if (client) {
          client.logout({ 
            logoutParams: { 
              returnTo: window.location.origin 
            } 
          });
        }
      }

      export async function getToken(): Promise<string | null> {
        const client = get(auth0Client);
        if (!client) return null;
        
        try {
          return await client.getTokenSilently();
        } catch (err: any) {
          if (err.error === 'login_required') {
            await login();
          }
          return null;
        }
      }
    ```
  </Step>

  <Step title="Créer les composants de connexion, de déconnexion et de profil" stepNumber={5}>
    Créer des fichiers de composants

    <CodeGroup>
      ```shellscript Mac/Linux theme={null}
      mkdir -p src/lib/components && touch src/lib/components/LoginButton.svelte && touch src/lib/components/LogoutButton.svelte && touch src/lib/components/Profile.svelte
      ```

      ```powershell Windows theme={null}
      New-Item -ItemType Directory -Force -Path src/lib/components
      New-Item -ItemType File -Path src/lib/components/LoginButton.svelte
      New-Item -ItemType File -Path src/lib/components/LogoutButton.svelte
      New-Item -ItemType File -Path src/lib/components/Profile.svelte
      ```
    </CodeGroup>

    Et ajoutez les extraits de code suivants

    <AuthCodeGroup>
      ```svelte src/lib/components/LoginButton.svelte lines expandable theme={null}
      <script lang="ts">
        import { login } from '$lib/stores/auth';

        async function handleLogin() {
          await login();
        }
      </script>

      <button 
        on:click={handleLogin}
        class="button login"
      >
        Log In
      </button>

      <style>
        .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);
        }
      </style>
      ```

      ```svelte src/lib/components/LogoutButton.svelte lines expandable theme={null}
      <script lang="ts">
        import { logout } from '$lib/stores/auth';

        async function handleLogout() {
          await logout();
        }
      </script>

      <button
        on:click={handleLogout}
        class="button logout"
      >
        Log Out
      </button>

      <style>
        .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(252, 129, 129, 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);
        }
      </style>
      ```

      ```svelte src/lib/components/Profile.svelte lines expandable theme={null}
      <script lang="ts">
        import { user, isAuthenticated, isLoading } from '$lib/stores/auth';
        
        const placeholderImage = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='50' fill='%2363b3ed'/%3E%3Cpath d='M50 45c7.5 0 13.64-6.14 13.64-13.64S57.5 17.72 50 17.72s-13.64 6.14-13.64 13.64S42.5 45 50 45zm0 6.82c-9.09 0-27.28 4.56-27.28 13.64v3.41c0 1.88 1.53 3.41 3.41 3.41h47.74c1.88 0 3.41-1.53 3.41-3.41v-3.41c0-9.08-18.19-13.64-27.28-13.64z' fill='%23fff'/%3E%3C/svg%3E`;
        
        function handleImageError(event: Event) {
          const target = event.target as HTMLImageElement;
          target.src = placeholderImage;
        }
      </script>

      {#if $isLoading}
        <div class="loading-text">Loading profile...</div>
      {:else if $isAuthenticated && $user}
        <div class="profile-container">
          <img 
            src={$user.picture || placeholderImage} 
            alt={$user.name || 'User'} 
            class="profile-picture"
            on:error={handleImageError}
          />
          <div class="profile-info">
            <div class="profile-name">
              {$user.name || 'Unknown User'}
            </div>
            <div class="profile-email">
              {$user.email || ''}
            </div>
          </div>
        </div>
      {/if}

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

        .profile-container {
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 1rem;
        }

        .profile-picture {
          width: 110px;
          height: 110px;
          border-radius: 50%;
          object-fit: cover;
          border: 3px solid #63b3ed;
          transition: transform 0.3s ease-in-out;
        }

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

        .profile-info {
          text-align: center;
        }

        .profile-name {
          font-size: 2rem;
          font-weight: 600;
          color: #f7fafc;
          margin-bottom: 0.5rem;
        }

        .profile-email {
          font-size: 1.15rem;
          color: #a0aec0;
        }

        @keyframes pulse {
          0%, 100% { opacity: 1; }
          50% { opacity: 0.6; }
        }
      </style>
      ```

      ```svelte src/routes/+layout.svelte expandable lines theme={null}
      <script lang="ts">
        import { onMount } from 'svelte';
        import { initializeAuth } from '$lib/stores/auth';

        onMount(() => {
          initializeAuth();
        });
      </script>

      <main>
        <slot />
      </main>

      <style>
        :global(body) {
          margin: 0;
          font-family: 'Inter', sans-serif;
          background-color: #1a1e27;
          min-height: 100vh;
          color: #e2e8f0;
        }

        main {
          min-height: 100vh;
          display: flex;
          justify-content: center;
          align-items: center;
          padding: 1rem;
          box-sizing: border-box;
        }
      </style>
      ```

      ```svelte src/routes/+page.svelte expandable lines theme={null}
      <script lang="ts">
        import { isAuthenticated, isLoading, error, user } from '$lib/stores/auth';
        import LoginButton from '$lib/components/LoginButton.svelte';
        import LogoutButton from '$lib/components/LogoutButton.svelte';
        import Profile from '$lib/components/Profile.svelte';
      </script>

      <svelte:head>
        <title>Auth0 Svelte Sample</title>
        <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
      </svelte:head>

      <div class="app-container">
        {#if $isLoading}
          <div class="loading-state">
            <div class="loading-text">Loading...</div>
          </div>
        {:else if $error}
          <div class="error-state">
            <div class="error-title">Oops!</div>
            <div class="error-message">Something went wrong</div>
            <div class="error-sub-message">{$error}</div>
          </div>
        {:else}
          <div class="main-card-wrapper">
            <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>

            {#if $isAuthenticated}
              <div class="logged-in-section">
                <div class="logged-in-message">✅ Successfully authenticated!</div>
                <h2 class="profile-section-title">Your Profile</h2>
                <div class="profile-card">
                  <Profile />
                </div>
                <LogoutButton />
              </div>
            {:else}
              <div class="action-card">
                <p class="action-text">Get started by signing in to your account</p>
                <LoginButton />
              </div>
            {/if}
          </div>
        {/if}
      </div>

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

        .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;
        }

        .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;
        }

        @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); }
        }

        @media (max-width: 600px) {
          .main-card-wrapper {
            padding: 2rem;
            margin: 1rem;
          }

          .main-title {
            font-size: 2.2rem;
          }

          .auth0-logo {
            width: 120px;
          }
        }
      </style>
      ```
    </AuthCodeGroup>
  </Step>

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

<Check>
  **Point de contrôle**

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

***

<div id="troubleshooting">
  ## Dépannage
</div>

<Accordion title="La connexion ne fonctionne pas">
  Si rien ne se passe lorsque vous cliquez sur le bouton de connexion :

  1. Ouvrez les outils de développement du navigateur (F12) et vérifiez l’onglet Console
  2. Vérifiez que le fichier `.env` contient de vrais identifiants Auth0
  3. Vérifiez que l’application Auth0 a les bonnes URL de rappel configurées
  4. Assurez-vous que `VITE_AUTH0_DOMAIN` contient uniquement le domaine (par ex., `tenant.auth0.com`), sans `https://`
</Accordion>

<Accordion title="Erreurs d’authentification">
  **"Callback URL mismatch"** :

  * Allez dans Auth0 Dashboard → Applications → Your App → Settings
  * Ajoutez `http://localhost:5173` à Allowed Callback URLs, Allowed Logout URLs et Allowed Web Origins
  * Cliquez sur "Save Changes"

  **"Invalid state"** :

  * Effacez le cache et les témoins du navigateur
  * Essayez dans une fenêtre de navigation privée/incognito
</Accordion>

<Accordion title="Problèmes du serveur de développement">
  Si `npm run dev` échoue :

  * Exécutez `npm run check` pour afficher les erreurs TypeScript
  * Vérifiez que tous les fichiers ont été créés correctement
  * Vérifiez que toutes les dépendances sont installées : `npm install`
</Accordion>

<Tip>
  Vous êtes toujours bloqué? Consultez la [communauté Auth0](https://community.auth0.com/) ou le [Discord de SvelteKit](https://svelte.dev/chat) pour obtenir de l’aide.
</Tip>
