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

# Ajouter la connexion à votre application TanStack Start

> Ce guide explique comment intégrer Auth0 à une application TanStack Start React à l'aide du SDK Auth0 TanStack Start React.

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

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  **Prérequis :** avant de commencer, assurez-vous d'avoir installé les éléments suivants :

  * **[Node.js](https://nodejs.org/en/download)** 20 LTS ou plus récent
  * **[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`
</Callout>

<Warning>
  `@auth0/auth0-tanstack-start-react` est actuellement en version **beta** (`1.0.0-beta.0`). L'API pourrait changer avant la sortie de la version stable 1.0.
</Warning>

<h2 id="get-started">
  Démarrer
</h2>

Ce Quickstart montre comment ajouter l'authentication Auth0 à une application TanStack Start React. Vous créerez une application rendue côté serveur comprenant le connexion, le logout, des routes protégées et les renseignements du profil utilisateur, à l'aide du SDK Auth0 TanStack Start React.

export function generateRandomString(length) {
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  return Array.from({
    length
  }, () => chars[Math.floor(Math.random() * chars.length)]).join('');
}

export const localEnvSnippet = `AUTH0_DOMAIN={yourDomain}
AUTH0_CLIENT_ID={yourClientId}
AUTH0_CLIENT_SECRET={yourClientSecret}
AUTH0_SECRET=${generateRandomString(32)}
APP_BASE_URL=http://localhost:3000`;

<Steps>
  <Step title="Créer un nouveau projet" stepNumber={1}>
    Générez la structure d'un nouveau projet TanStack Start pour ce Quickstart :

    ```shellscript theme={null}
    npx @tanstack/cli@latest create auth0-tanstack-start --blank --package-manager npm -y
    ```

    <Info>
      Si c'est la première fois que vous exécutez `@tanstack/cli` sur votre machine, npm vous demandera de confirmer son installation : répondez **y** pour continuer.
    </Info>

    Ouvrez le projet :

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

  <Step title="Installez le SDK Auth0 TanStack Start" stepNumber={2}>
    ```shellscript theme={null}
    npm install @auth0/auth0-tanstack-start-react
    ```
  </Step>

  <Step title="Ajouter Tailwind CSS" stepNumber={3}>
    Installez Tailwind CSS et son plugin Vite :

    ```shellscript theme={null}
    npm install tailwindcss @tailwindcss/vite
    ```

    Modifiez `vite.config.ts` pour ajouter le plugin Tailwind et fixer le serveur de développement au `port 3000` :

    ```typescript vite.config.ts {2,7} lines theme={null}
    import { defineConfig } from 'vite';
    import tailwindcss from '@tailwindcss/vite';
    import { tanstackStart } from '@tanstack/react-start/plugin/vite';
    import viteReact from '@vitejs/plugin-react';

    const config = defineConfig({
      server: { strictPort: true },
      resolve: { tsconfigPaths: true },
      plugins: [tailwindcss(), tanstackStart(), viteReact()],
    });

    export default config;
    ```

    <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
      Vite échoue immédiatement lorsque vous utilisez `strictPort: true`, plutôt que de changer de port sans avertissement. La callback URL de votre Auth0 application est verrouillée sur le port 3000 : comme le navigateur est redirigé vers un port sur lequel rien n'écoute, un changement de port silencieux vous laisse coincé devant une page blanche après avoir approuvé le login screen.
    </Callout>

    Remplacez le contenu de `src/styles.css` par :

    ```css src/styles.css lines theme={null}
    @import "tailwindcss";
    ```
  </Step>

  <Step title="Créer les fichiers du projet" stepNumber={4}>
    Créez les fichiers supplémentaires nécessaires à l'integration Auth0 :

    <CodeGroup>
      ```shellscript Mac/Linux theme={null}
      mkdir -p src/components && touch .env src/start.ts src/auth.server.ts src/components/LoginButton.tsx src/components/LogoutButton.tsx src/components/Profile.tsx src/routes/dashboard.tsx
      ```

      ```powershell Windows theme={null}
      New-Item -ItemType Directory -Force -Path src/components
      New-Item -ItemType File -Path .env, src/start.ts, src/auth.server.ts, src/components/LoginButton.tsx, src/components/LogoutButton.tsx, src/components/Profile.tsx, src/routes/dashboard.tsx
      ```
    </CodeGroup>
  </Step>

  <Step title="Configurez votre Auth0 App" stepNumber={5}>
    L'étape suivante consiste à créer une nouvelle application dans votre tenant Auth0, puis à ajouter les variables d'environnement à votre projet.

    Vous disposez de trois options pour configurer votre Auth0 App : utiliser l’outil de configuration rapide (recommandé), exécuter une commande CLI ou procéder à la configuration manuelle à partir du Dashboard :

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

        <CreateInteractiveApp placeholderText="TanStack Start" appType="regular_web" allowedCallbackUrls={["http://localhost:3000/auth/callback"]} allowedLogoutUrls={["http://localhost:3000"]} allowedOriginUrls={["http://localhost:3000"]} />

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

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

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

          # Configurer l'Auth0 App et générer un fichier .env
          auth0 qs setup --app --type regular --name "My App" --port 3000
          ```

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

          # Configurer l'Auth0 App et générer le fichier .env
          auth0 qs setup --app --type regular --name "My App" --port 3000
          ```
        </CodeGroup>

        <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
          Cette commande :

          1. Vérifie si vous êtes authentifié (et vous invite à vous connecter au besoin)
          2. Crée une Auth0 Regular Web Application configurée pour `http://localhost:3000`
          3. Génère un fichier `.env` contenant `AUTH0_DOMAIN`, `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET`, `AUTH0_SECRET` et `APP_BASE_URL`
        </Callout>
      </Tab>

      <Tab title="Dashboard">
        Ouvrez le fichier `.env` que vous avez créé à l'étape 4 et ajoutez :

        ```shellscript .env theme={null}
        AUTH0_DOMAIN=YOUR_AUTH0_APP_DOMAIN
        AUTH0_CLIENT_ID=YOUR_AUTH0_APP_CLIENT_ID
        AUTH0_CLIENT_SECRET=YOUR_AUTH0_APP_CLIENT_SECRET
        AUTH0_SECRET=YOUR_LONG_RANDOM_SECRET_HERE
        APP_BASE_URL=http://localhost:3000
        ```

        **Générez un AUTH0\_SECRET sécuritaire :**

        ```shellscript theme={null}
        openssl rand -hex 32
        ```

        Copiez le résultat et remplacez `YOUR_LONG_RANDOM_SECRET_HERE` dans le fichier `.env`. Il doit compter exactement 64 caractères hexadécimaux.

        Configurez ensuite votre application Auth0 :

        1. Accédez à l'[Auth0 Dashboard](https://manage.auth0.com/dashboard/)
        2. Sélectionnez **Applications** > **Applications** > **Create Application**
        3. Saisissez un nom pour votre app, sélectionnez **Regular Web Application** comme type d'app, puis sélectionnez **Create**
        4. Passez à l'onglet **Settings** de la page Application Details
        5. Dans le fichier `.env`, remplacez `YOUR_AUTH0_APP_DOMAIN`, `YOUR_AUTH0_APP_CLIENT_ID` et `YOUR_AUTH0_APP_CLIENT_SECRET` par les valeurs **Domain**, **Client ID** et **Client Secret** affichées dans le dashboard

        <Warning>
          **Essentiel :** `AUTH0_DOMAIN`, `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET`, `AUTH0_SECRET` et `APP_BASE_URL` sont lues uniquement sur le serveur. Ne les préfixez jamais avec `VITE_`, sinon leurs valeurs se retrouveront dans le bundle JavaScript côté client.
        </Warning>

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

        **Allowed Callback URLs :**

        ```
        http://localhost:3000/auth/callback
        ```

        **Allowed Logout URLs :**

        ```
        http://localhost:3000
        ```

        **Allowed Web Origins :**

        ```
        http://localhost:3000
        ```

        <Info>
          * Les Allowed Callback URLs constituent une mesure de sécurité essentielle : elles garantissent que les utilisateurs sont ramenés en toute sécurité vers votre application après l'authentification. Sans URL correspondante, le login process échoue et les utilisateurs finaux se retrouvent bloqués devant une page d'erreur Auth0 au lieu d'accéder à votre app.
          * Les Allowed Logout URLs sont essentielles pour offrir une expérience utilisateur fluide à la déconnexion. Sans URL correspondante, les utilisateurs finaux ne sont pas redirigés vers votre application après le logout et restent sur une page Auth0 générique.
          * Les Allowed Web Origins sont essentielles à l'authentification silencieuse. Sans elles, les utilisateurs sont déconnectés dès qu'ils actualisent la page ou reviennent à votre app plus tard.
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Créez l’instance du serveur Auth0" stepNumber={6}>
    Ajoutez l'instance Auth0 server dans `src/auth.server.ts`. L'instance Auth0 server lit la configuration à partir des environment variables que vous venez de définir :

    ```typescript src/auth.server.ts lines theme={null}
    import { auth0Server } from '@auth0/auth0-tanstack-start-react/server';

    export const auth0 = auth0Server();
    ```
  </Step>

  <Step title="Enregistrez le middleware Auth0" stepNumber={7}>
    Ajoutez ce qui suit à `src/start.ts` pour enregistrer le middleware de requête Auth0 :

    ```typescript src/start.ts lines theme={null}
    import { createStart } from '@tanstack/react-start';
    import { auth0Middleware } from '@auth0/auth0-tanstack-start-react/server/middleware';

    export const startInstance = createStart(() => ({
      requestMiddleware: [auth0Middleware()],
    }));
    ```

    <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
      Importez `auth0Middleware` depuis le sous-chemin `/server/middleware`, et non depuis le fichier barrel `/server`, puisque `start.ts` est également compilé dans le bundle client.
    </Callout>

    <Info>
      Ce middleware monte automatiquement les routes d'authentication suivantes :

      * `/auth/login` - Route de login
      * `/auth/callback` - Route de callback
      * `/auth/logout` - Route de logout
      * `/auth/profile` - Route du profil utilisateur
      * `/auth/backchannel-logout` - Route de logout par canal secondaire
    </Info>
  </Step>

  <Step title="Intégrez Auth0 au router" stepNumber={8}>
    Modifiez `src/router.tsx` afin que le context du router contienne l'état d'authentification résolu par Auth0. TanStack Start exige que ce fichier exporte une fonction nommée `getRouter` :

    ```typescript src/router.tsx {2,3,7,9,13} lines theme={null}
    import { createRouter as createTanStackRouter } from '@tanstack/react-router';
    import { auth0RouterContext } from '@auth0/auth0-tanstack-start-react/client';
    import type { Auth0RouterContext } from '@auth0/auth0-tanstack-start-react/types';
    import { routeTree } from './routeTree.gen';

    export interface RouterContext {
      auth0: Auth0RouterContext;
    }

    export function getRouter() {
      const router = createTanStackRouter({
        routeTree,
        scrollRestoration: true,
        defaultPreload: 'intent',
        defaultPreloadStaleTime: 0,
        context: { auth0: auth0RouterContext } satisfies RouterContext,
      });

      return router;
    }

    declare module '@tanstack/react-router' {
      interface Register {
        router: ReturnType<typeof getRouter>;
      }
    }
    ```
  </Step>

  <Step title="Mettre à jour la route racine" stepNumber={9}>
    Modifiez `src/routes/__root.tsx` pour résoudre le state d'authentification avant le render et encapsuler l'application dans `Auth0Provider` :

    ```typescript src/routes/__root.tsx expandable lines theme={null}
    import {
      HeadContent,
      Scripts,
      createRootRouteWithContext,
    } from '@tanstack/react-router';
    import { Auth0Provider, auth0BeforeLoad } from '@auth0/auth0-tanstack-start-react/client';

    import type { RouterContext } from '../router';
    import appCss from '../styles.css?url';

    export const Route = createRootRouteWithContext<RouterContext>()({
      beforeLoad: auth0BeforeLoad(),
      head: () => ({
        meta: [
          { charSet: 'utf-8' },
          { name: 'viewport', content: 'width=device-width, initial-scale=1' },
          { title: 'Auth0 + TanStack Start' },
        ],
        links: [{ rel: 'stylesheet', href: appCss }],
      }),
      shellComponent: RootDocument,
    });

    function RootDocument({ children }: { children: React.ReactNode }) {
      return (
        <html lang="en">
          <head>
            <HeadContent />
          </head>
          <body className="antialiased">
            <Auth0Provider>{children}</Auth0Provider>
            <Scripts />
          </body>
        </html>
      );
    }
    ```

    <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
      Cela remplace `createRootRoute` par `createRootRouteWithContext<RouterContext>()`, ce qui permet de typer l'arborescence des routes avec `context.auth0`.
    </Callout>
  </Step>

  <Step title="Créer des composants Login, Logout et profil" stepNumber={10}>
    Ajoutez le code du composant aux fichiers créés à l'étape 4 :

    <AuthCodeGroup>
      ```typescript src/components/LoginButton.tsx lines theme={null}
      import { useLogin } from "@auth0/auth0-tanstack-start-react/client";

      export default function LoginButton() {
        const login = useLogin();

        return (
          <button
            onClick={() => login("/dashboard")}
            className="w-full text-center inline-block px-6 py-3 bg-gradient-to-b from-[#2d2d42] to-[#161620] hover:opacity-90 text-white font-medium rounded-full text-[14px] transition-opacity"
          >
            Log In
          </button>
        );
      }
      ```

      ```typescript src/components/LogoutButton.tsx lines theme={null}
      import { useLogout } from "@auth0/auth0-tanstack-start-react/client";

      export default function LogoutButton() {
        const logout = useLogout();

        return (
          <button
            onClick={() => logout()}
            className="w-full text-center inline-block px-6 py-3 bg-[#f0f0f0] hover:bg-gray-200 text-gray-600 font-medium rounded-full text-[14px] transition-colors"
          >
            Log Out
          </button>
        );
      }
      ```

      ```typescript src/components/Profile.tsx lines theme={null}
      import { useUser } from "@auth0/auth0-tanstack-start-react/client";

      function getInitials(name?: string | null, email?: string | null): string {
        if (name) {
          const parts = name.trim().split(" ");
          return parts.length >= 2
            ? `${parts[0][0]}${parts[1][0]}`.toUpperCase()
            : parts[0].slice(0, 2).toUpperCase();
        }
        if (email) return email.slice(0, 2).toUpperCase();
        return "U";
      }

      export default function Profile() {
        const user = useUser();

        if (!user) return null;

        return (
          <div className="flex items-center gap-2 bg-gray-100 rounded-full py-1.5 pl-1.5 pr-4 text-[12px] text-gray-700 max-w-full">
            <span className="w-7 h-7 bg-gradient-to-b from-[#2d2d42] to-[#161620] rounded-full flex items-center justify-center text-white text-[10px] font-semibold shrink-0">
              {getInitials(user.name, user.email)}
            </span>
            <span className="truncate">{user.email}</span>
          </div>
        );
      }
      ```
    </AuthCodeGroup>

    Remplacez ensuite le contenu par défaut de `src/routes/index.tsx` (la page `Welcome to TanStack Start` générée par le gabarit) par :

    ```typescript src/routes/index.tsx lines theme={null}
    import { createFileRoute } from "@tanstack/react-router";
    import { SignedIn, SignedOut } from "@auth0/auth0-tanstack-start-react/client";
    import LoginButton from "../components/LoginButton";
    import LogoutButton from "../components/LogoutButton";
    import Profile from "../components/Profile";

    export const Route = createFileRoute("/")({
      component: Home,
    });

    function Home() {
      return (
        <main className="min-h-screen bg-[#efefef] flex flex-col items-center justify-center gap-4 px-6 py-12">
          <div className="bg-white rounded-[28px] shadow-[0_4px_32px_rgba(0,0,0,0.08)] px-12 py-14 flex flex-col items-center gap-4 w-[360px]">
            <svg width="68" height="68" viewBox="0 0 68 68" fill="none" xmlns="http://www.w3.org/2000/svg" className="mb-1">
              <g filter="url(#filter0_di)">
                <rect x="2" y="2" width="64" height="64" rx="16" fill="url(#paint0_linear)"/>
                <rect x="2.5" y="2.5" width="63" height="63" rx="15.5" stroke="#252525"/>
                <path d="M34.0002 18C25.1572 18 18 25.1669 18 34C18 42.8432 25.1672 50 34.0002 50C42.8333 50 50 42.8331 50 34C50 25.1669 42.8433 18 34.0002 18ZM43.9172 43.8971C43.9172 43.9071 43.9069 43.9072 43.9069 43.9172C43.9069 43.9172 43.8969 43.9272 43.8868 43.9272C43.144 44.65 41.9796 44.7303 41.0662 44.2585L40.0228 43.7265C36.2487 41.7792 31.7619 41.7792 27.9777 43.7265L26.9338 44.2585C26.0103 44.7303 24.8459 44.65 24.1132 43.9272C24.1132 43.9272 24.1031 43.9172 24.0931 43.9172C24.0931 43.9172 24.0828 43.9071 24.0828 43.8971C23.3601 43.1543 23.2797 41.9899 23.7515 41.0765L24.2837 40.0326C26.231 36.2585 26.231 31.7717 24.2837 27.9975L23.7515 26.9536C23.2797 26.0302 23.3601 24.8657 24.0828 24.133C24.0828 24.1229 24.0931 24.123 24.0931 24.123C24.0931 24.123 24.1031 24.1129 24.1132 24.1129C24.856 23.3902 26.0204 23.3099 26.9338 23.7817L27.9777 24.3137C31.7518 26.261 36.2386 26.261 40.0228 24.3137L41.0662 23.7817C41.9897 23.3099 43.1541 23.3902 43.8868 24.1129C43.8868 24.1129 43.8969 24.123 43.9069 24.123L43.9172 24.133C44.6399 24.8758 44.7203 26.0402 44.2485 26.9536L43.7163 27.9975C41.769 31.7717 41.769 36.2585 43.7163 40.0326L44.2485 41.0765C44.7203 41.9899 44.6499 43.1543 43.9172 43.8971Z" fill="white"/>
              </g>
              <defs>
                <filter id="filter0_di" x="0" y="0" width="68" height="68" filterUnits="userSpaceOnUse" colorInterpolationFilters="sRGB">
                  <feFlood floodOpacity="0" result="BackgroundImageFix"/>
                  <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
                  <feMorphology radius="2" operator="dilate" in="SourceAlpha" result="effect1_dropShadow"/>
                  <feOffset/>
                  <feComposite in2="hardAlpha" operator="out"/>
                  <feColorMatrix type="matrix" values="0 0 0 0 0.117647 0 0 0 0 0.129412 0 0 0 0 0.164706 0 0 0 0.12 0"/>
                  <feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
                  <feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
                  <feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
                  <feOffset dy="-1"/>
                  <feGaussianBlur stdDeviation="0.5"/>
                  <feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
                  <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.04 0"/>
                  <feBlend mode="normal" in2="shape" result="effect2_innerShadow"/>
                </filter>
                <linearGradient id="paint0_linear" x1="34" y1="2" x2="34" y2="66" gradientUnits="userSpaceOnUse">
                  <stop/>
                  <stop offset="1" stopColor="#677190"/>
                </linearGradient>
              </defs>
            </svg>

            <SignedIn>
              <h1 className="text-[17px] font-bold text-gray-900 tracking-tight">Your account</h1>
              <div className="w-full h-px bg-gray-100" />
              <Profile />
              <LogoutButton />
            </SignedIn>
            <SignedOut>
              <h1 className="text-[17px] font-bold text-gray-900 tracking-tight">Welcome to Auth0 + TanStack Start</h1>
              <p className="text-[13px] text-gray-400 text-center leading-relaxed -mt-2">
                Get started by logging in to your account
              </p>
              <div className="h-3" />
              <LoginButton />
            </SignedOut>
          </div>

          <div className="flex items-center gap-1.5 text-[11px] text-gray-400">
            <span>Powered by</span>
            <img
              src="https://cdn.auth0.com/quantum-assets/dist/latest/logos/auth0/auth0-lockup-en-onlight.svg"
              alt="Auth0"
              className="h-3 opacity-40"
            />
          </div>
        </main>
      );
    }
    ```

    <Info>
      `useLogin` et `useLogout` déclenchent une navigation complète du navigateur plutôt qu'une transition de router client-side, car `/auth/*` est géré par le middleware côté serveur et le session cookie nécessite un rechargement de la page pour prendre effet.
    </Info>
  </Step>

  <Step title="Protéger une route" stepNumber={11}>
    Ajoutez une route protégée `/dashboard` dans `src/routes/dashboard.tsx` à l'aide du garde `requireAuth`. Celui-ci redirige les utilisateurs non authentifiés vers `/auth/login` du côté serveur, avant que le moindre code HTML ne soit envoyé au navigateur :

    ```typescript src/routes/dashboard.tsx lines theme={null}
    import { createFileRoute } from "@tanstack/react-router";
    import { requireAuth, useUser } from "@auth0/auth0-tanstack-start-react/client";
    import LogoutButton from "../components/LogoutButton";
    import Profile from "../components/Profile";

    export const Route = createFileRoute("/dashboard")({
      beforeLoad: requireAuth({ returnTo: "/dashboard" }),
      component: Dashboard,
    });

    function Dashboard() {
      const user = useUser();

      return (
        <main className="min-h-screen bg-[#efefef] flex flex-col items-center justify-center gap-4 px-6 py-12">
          <div className="bg-white rounded-[28px] shadow-[0_4px_32px_rgba(0,0,0,0.08)] px-12 py-14 flex flex-col items-center gap-4 w-[360px]">
            <h1 className="text-[17px] font-bold text-gray-900 tracking-tight">Welcome, {user?.name}!</h1>
            <div className="w-full h-px bg-gray-100" />
            <Profile />
            <LogoutButton />
          </div>
        </main>
      );
    }
    ```
  </Step>

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

    <Info>
      Votre application est accessible à l'adresse [http://localhost:3000](http://localhost:3000).
    </Info>
  </Step>
</Steps>

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

  Vous devriez maintenant avoir une page de connexion Auth0 entièrement fonctionnelle qui s'exécute sur votre [localhost](http://localhost:3000/)
</Check>
