> ## 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.

# Ajouter la connexion à votre application React

> Ce guide explique comment intégrer Auth0, ajouter l’authentification et afficher les informations du profil utilisateur dans une application monopage (SPA) utilisant React, à l’aide du SDK React d’Auth0.

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

<Accordion title="Utilisez l’IA pour intégrer Auth0" icon="microchip-ai" iconType="solid" defaultOpen>
  Si vous utilisez un assistant de codage par IA comme Claude Code, Cursor ou GitHub Copilot, vous pouvez ajouter automatiquement l’authentification Auth0 en quelques minutes à l’aide des [agent skills](https://agentskills.io/home).

  **Installation :**

  ```bash theme={null}
  npx skills add auth0/agent-skills --skill auth0-quickstart --skill auth0-react
  ```

  **Demandez ensuite à votre assistant IA :**

  ```text theme={null}
  Add Auth0 authentication to my React app
  ```

  Votre assistant IA créera automatiquement votre application Auth0, récupérera les identifiants, installera `@auth0/auth0-react`, configurera Auth0Provider et créera tous les composants nécessaires. [Documentation complète sur les agent skills →](/fr-CA/docs/quickstart/agent-skills)
</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`

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

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

Ce guide de démarrage rapide vous montre comment ajouter l’authentification Auth0 à une application React. Vous créerez une application monopage sécurisée avec des fonctionnalités de connexion, de déconnexion et de profil utilisateur à l’aide du SDK React d’Auth0.

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

<Steps>
  <Step title="Créer un projet" stepNumber={1}>
    Créez un nouveau projet React pour ce guide de démarrage

    ```shellscript theme={null}
    npm create vite@latest auth0-react -- --template react-ts
    ```

    Ouvrez le projet

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

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

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

    Vous avez trois options pour configurer votre application Auth0 : utiliser l’outil Quick Setup (recommandé), exécuter une commande CLI ou la configurer manuellement dans le 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="React" 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 react --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 react --build-tool vite --name "My App" --port 5173
          ```
        </CodeGroup>

        <Note>
          Cette commande permet de :

          1. Vérifier si vous êtes authentifié (et demander une connexion au besoin)
          2. Créer une application monopage Auth0 configurée pour `http://localhost:5173`
          3. Générer un fichier `.env` contenant `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, entrez un nom pour votre application, sélectionnez `Single Page Web Application` comme type d’application, puis cliquez sur **Create**
        4. Ouvrez l’onglet **Settings** de 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 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>
          **Allowed Callback URLs** est une mesure de sécurité essentielle pour que les utilisateurs soient redirigés de façon sécuritaire 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** est essentiel pour offrir une expérience fluide lors de 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 cela, les utilisateurs seront déconnectés lorsqu’ils actualiseront la page ou reviendront plus tard dans votre application.
        </Info>
      </Tab>
    </Tabs>

    <Tip>
      Vérifiez que votre fichier `.env` existe : `cat .env` (Mac/Linux) ou `type .env` (Windows)
    </Tip>
  </Step>

  <Step title="Ajouter le fournisseur" stepNumber={4}>
    ```javascript src/main.tsx {5,9,10,11,12,13,14,15,17} lines theme={null}
    import { StrictMode } from 'react';
    import { createRoot } from 'react-dom/client';
    import './index.css'; // Importation du fichier CSS principal
    import App from './App.tsx';
    import { Auth0Provider } from '@auth0/auth0-react';

    createRoot(document.getElementById('root')!).render(
      <StrictMode>
        <Auth0Provider
          domain={import.meta.env.VITE_AUTH0_DOMAIN}
          clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
          authorizationParams={{
            redirect_uri: window.location.origin
          }}
        >
          <App />
        </Auth0Provider>
      </StrictMode>
    );
    ```
  </Step>

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

    <CodeGroup>
      ```shellscript Mac/Linux theme={null}
      touch src/LoginButton.tsx && touch src/LogoutButton.tsx && touch src/Profile.tsx
      ```

      ```powershell Windows theme={null}
      New-Item -ItemType File -Path src/LoginButton.tsx
      New-Item -ItemType File -Path src/LogoutButton.tsx
      New-Item -ItemType File -Path src/Profile.tsx
      ```
    </CodeGroup>

    Et ajoutez les extraits de code suivants

    <AuthCodeGroup>
      ```javascript src/LoginButton.tsx lines theme={null}
      import { useAuth0 } from "@auth0/auth0-react";

      const LoginButton = () => {
        const { loginWithRedirect } = useAuth0();
        return (
          <button 
            onClick={() => loginWithRedirect()} 
            className="button login"
          >
            Log In
          </button>
        );
      };

      export default LoginButton;
      ```

      ```javascript src/LogoutButton.tsx lines theme={null}
      import { useAuth0 } from "@auth0/auth0-react";

      const LogoutButton = () => {
        const { logout } = useAuth0();
        return (
          <button
            onClick={() => logout({ logoutParams: { returnTo: window.location.origin } })}
            className="button logout"
          >
            Log Out
          </button>
        );
      };

      export default LogoutButton;
      ```

      ```javascript src/Profile.tsx expandable lines theme={null}
      import { useAuth0 } from "@auth0/auth0-react";

      const Profile = () => {
        const { user, isAuthenticated, isLoading } = useAuth0();

        if (isLoading) {
          return <div className="loading-text">Loading profile...</div>;
        }

        return (
          isAuthenticated && user ? (
            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '1rem' }}>
              <img 
                src={user.picture || `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`} 
                alt={user.name || 'User'} 
                className="profile-picture"
                style={{ 
                  width: '110px', 
                  height: '110px', 
                  borderRadius: '50%', 
                  objectFit: 'cover',
                  border: '3px solid #63b3ed'
                }}
                onError={(e) => {
                  const target = e.target as HTMLImageElement;
                  target.src = `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`;
                }}
              />
              <div style={{ textAlign: 'center' }}>
                <div className="profile-name" style={{ fontSize: '2rem', fontWeight: '600', color: '#f7fafc', marginBottom: '0.5rem' }}>
                  {user.name}
                </div>
                <div className="profile-email" style={{ fontSize: '1.15rem', color: '#a0aec0' }}>
                  {user.email}
                </div>
              </div>
            </div>
          ) : null
        );
      };

      export default Profile;
      ```

      ```javascript src/App.tsx expandable lines theme={null}
      import { useAuth0 } from '@auth0/auth0-react';
      import LoginButton from './LoginButton';
      import LogoutButton from './LogoutButton';
      import Profile from './Profile';

      function App() {
        const { isAuthenticated, isLoading, error } = useAuth0();

        if (isLoading) {
          return (
            <div className="app-container">
              <div className="loading-state">
                <div className="loading-text">Loading...</div>
              </div>
            </div>
          );
        }

        if (error) {
          return (
            <div className="app-container">
              <div className="error-state">
                <div className="error-title">Oops!</div>
                <div className="error-message">Something went wrong</div>
                <div className="error-sub-message">{error.message}</div>
              </div>
            </div>
          );
        }

        return (
          <div className="app-container">
            <div className="main-card-wrapper">
              <img 
                src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-ondark.png" 
                alt="Auth0 Logo" 
                className="auth0-logo"
                onError={(e) => {
                  e.currentTarget.style.display = 'none';
                }}
              />
              <h1 className="main-title">Welcome to Sample0</h1>
              
              {isAuthenticated ? (
                <div className="logged-in-section">
                  <div className="logged-in-message">✅ Successfully authenticated!</div>
                  <h2 className="profile-section-title">Your Profile</h2>
                  <div className="profile-card">
                    <Profile />
                  </div>
                  <LogoutButton />
                </div>
              ) : (
                <div className="action-card">
                  <p className="action-text">Get started by signing in to your account</p>
                  <LoginButton />
                </div>
              )}
            </div>
          </div>
        );
      }

      export default App;
      ```

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

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

      #root {
        width: 100%;
        height: 100%;
        display: flex;
        justify-content: center;
        align-items: center;
      }

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

      .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 {
        width: 110px;
        transition: transform 0.3s ease-in-out;
      }

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

      .profile-name {
        font-size: 2rem;
        margin-top: 0.5rem;
      }

      .profile-email {
        font-size: 1.15rem;
        text-align: center;
      }

      @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;
        }
        
        .button {
          padding: 1rem 2rem;
          font-size: 1.1rem;
        }
        
        .auth0-logo {
          width: 120px;
        }
      }
      ```
    </AuthCodeGroup>
  </Step>

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

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

<Check>
  **Vérification**

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

***

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

<Accordion title="Protéger des routes avec React Router">
  Utilisez l’état d’authentification d’Auth0 pour protéger certaines routes de votre application :

  ```jsx src/App.jsx theme={null}
  import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
  import { useAuth0 } from '@auth0/auth0-react';
  import Profile from './components/Profile';
  import Dashboard from './components/Dashboard';
  import LoginButton from './components/LoginButton';

  function ProtectedRoute({ children }) {
    const { isAuthenticated, isLoading } = useAuth0();
    
    if (isLoading) return <div>Loading...</div>;
    
    return isAuthenticated ? children : <Navigate to="/" />;
  }

  function App() {
    return (
      <BrowserRouter>
        <Routes>
          <Route path="/" element={<LoginButton />} />
          <Route 
            path="/profile" 
            element={
              <ProtectedRoute>
                <Profile />
              </ProtectedRoute>
            } 
          />
          <Route 
            path="/dashboard" 
            element={
              <ProtectedRoute>
                <Dashboard />
              </ProtectedRoute>
            } 
          />
        </Routes>
      </BrowserRouter>
    );
  }
  ```
</Accordion>

<Accordion title="Appeler des API protégées">
  Configurez votre Auth0Provider pour inclure une audience d’API et utiliser la méthode `getAccessTokenSilently` :

  ```jsx src/main.jsx theme={null}
  import { Auth0Provider } from '@auth0/auth0-react';

  const root = ReactDOM.createRoot(document.getElementById('root'));

  root.render(
    <Auth0Provider
      domain={import.meta.env.VITE_AUTH0_DOMAIN}
      clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
      authorizationParams={{
        redirect_uri: window.location.origin,
        audience: "YOUR_API_IDENTIFIER"
      }}
    >
      <App />
    </Auth0Provider>
  );
  ```

  Effectuez ensuite des appels authentifiés à l’API :

  ```jsx src/components/ApiCall.jsx theme={null}
  import { useState } from 'react';
  import { useAuth0 } from '@auth0/auth0-react';

  function ApiCall() {
    const { getAccessTokenSilently } = useAuth0();
    const [apiResponse, setApiResponse] = useState(null);

    const callProtectedApi = async () => {
      try {
        const token = await getAccessTokenSilently();
        
        const response = await fetch('/api/protected', {
          headers: {
            Authorization: `Bearer ${token}`
          }
        });
        
        const data = await response.json();
        setApiResponse(data);
      } catch (error) {
        console.error('API call failed:', error);
      }
    };

    return (
      <div>
        <button onClick={callProtectedApi}>Call API</button>
        {apiResponse && <pre>{JSON.stringify(apiResponse, null, 2)}</pre>}
      </div>
    );
  }

  export default ApiCall;
  ```
</Accordion>

<Accordion title="Utiliser Auth0 avec des hooks personnalisés">
  Créez des hooks personnalisés réutilisables pour les scénarios d’authentification courants :

  ```jsx src/hooks/useAuthenticatedUser.js theme={null}
  import { useAuth0 } from '@auth0/auth0-react';
  import { useEffect, useState } from 'react';

  export function useAuthenticatedUser() {
    const { user, isAuthenticated, isLoading, getAccessTokenSilently } = useAuth0();
    const [accessToken, setAccessToken] = useState(null);

    useEffect(() => {
      if (isAuthenticated && !isLoading) {
        getAccessTokenSilently()
          .then(token => setAccessToken(token))
          .catch(console.error);
      }
    }, [isAuthenticated, isLoading, getAccessTokenSilently]);

    return {
      user,
      accessToken,
      isAuthenticated,
      isLoading
    };
  }
  ```

  Utilisation dans les composants :

  ```jsx src/components/UserDashboard.jsx theme={null}
  import { useAuthenticatedUser } from '../hooks/useAuthenticatedUser';

  function UserDashboard() {
    const { user, accessToken, isLoading } = useAuthenticatedUser();

    if (isLoading) return <div>Loading...</div>;

    return (
      <div>
        <h1>Welcome, {user?.name}</h1>
        <p>Access Token: {accessToken ? 'Available' : 'Not available'}</p>
      </div>
    );
  }
  ```
</Accordion>
