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

> Ce guide explique comment intégrer Auth0 à une application Next.js, nouvelle ou existante, à l’aide du SDK Auth0 Next.js v4.

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

  **Installer :**

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

  **Demandez ensuite à votre assistant IA :**

  ```text theme={null}
  Add Auth0 authentication to my Next.js app
  ```

  Votre assistant IA créera automatiquement votre application Auth0, récupérera les identifiants, installera `@auth0/nextjs-auth0`, créera les routes d’API et configurera les variables d’environnement. [Documentation complète des agent skills →](/fr-CA/docs/quickstart/agent-skills)
</Accordion>

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

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

Ce guide de démarrage rapide explique comment ajouter l’authentification Auth0 à une application Next.js 16. Vous créerez une application Web complète avec rendu côté serveur, un mécanisme de connexion sécurisé et des routes protégées à l’aide du SDK Next.js d’Auth0.

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}>
    Créez un nouveau projet Next.js pour ce guide de démarrage rapide

    ```shellscript theme={null}
    npx create-next-app@latest auth0-nextjs --typescript --tailwind --eslint --app --src-dir --import-alias "@/*" --yes
    ```

    Ouvrez le projet

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

  <Step title="Installer le SDK Auth0 pour Next.js" stepNumber={2}>
    `shellscript npm install @auth0/nextjs-auth0 `
  </Step>

  <Step title="Créer les fichiers du projet" stepNumber={3}>
    Créez tous les répertoires et fichiers nécessaires à l’intégration d’Auth0 :

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

      ```powershell Windows theme={null}
      New-Item -ItemType Directory -Force -Path src/lib, src/components
      New-Item -ItemType File -Path src/lib/auth0.ts, src/proxy.ts, src/components/LoginButton.tsx, src/components/LogoutButton.tsx, src/components/Profile.tsx
      ```
    </CodeGroup>
  </Step>

  <Step title="Configurez votre application Auth0" stepNumber={4}>
    Ensuite, créez une nouvelle application sur votre locataire Auth0 et ajoutez les variables d'environnement à votre projet.

    Vous disposez de trois options pour configurer votre application Auth0 : utiliser l'outil Quick Setup (recommandé), exécuter une commande CLI ou effectuer la configuration manuellement via le Auth0 Dashboard :

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

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

        <AuthCodeBlock children={localEnvSnippet} language="shellscript" filename=".env.local" />
      </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}
          # Installez Auth0 CLI (si ce n’est pas déjà fait)
          brew tap auth0/auth0-cli && brew install auth0

          # Configurez l’application Auth0 et générez le fichier .env
          auth0 qs setup --app --type regular --framework nextjs --name "My App" --port 3000
          ```

          ```powershell Windows theme={null}
          # Installez 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

          # Configurez l’application Auth0 et générez le fichier .env
          auth0 qs setup --app --type regular --framework nextjs --name "My App" --port 3000
          ```
        </CodeGroup>

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

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

      <Tab title="Auth0 Dashboard">
        Créez un fichier `.env.local` à la racine de votre projet :

        ```shellscript .env.local 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écurisé :**

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

        Copiez le résultat et remplacez `YOUR_LONG_RANDOM_SECRET_HERE` dans `.env.local`. La valeur doit comporter exactement 64 caractères hexadécimaux.

        Configurez ensuite votre application Auth0 :

        1. Accédez au [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
        2. Cliquez sur **Applications** > **Applications** > **Create Application**
        3. Dans la fenêtre qui s’ouvre, entrez un nom pour votre application, sélectionnez `Regular Web Application` comme type d’application, puis cliquez sur **Create**
        4. Ouvrez l’onglet **Settings** dans la page **Application Details**
        5. Remplacez `YOUR_AUTH0_APP_DOMAIN`, `YOUR_AUTH0_APP_CLIENT_ID` et `YOUR_AUTH0_APP_CLIENT_SECRET` dans le fichier `.env.local` par les valeurs **Domain**, **Client ID** et **Client Secret** du tableau de bord

        <Warning>
          **Critique :** Si vous modifiez `AUTH0_SECRET` après le démarrage de l’application, vous devez effacer les cookies de session de votre navigateur pour localhost. Les anciens cookies de session chiffrés avec le secret précédent provoqueront une erreur `JWEDecryptionFailed`.
        </Warning>

        Enfin, dans l’onglet **Settings** de votre 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>
          **Allowed Callback URLs** constituent une mesure de sécurité essentielle pour garantir que les utilisateurs sont redirigés de façon sécuritaire vers votre application après l’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 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 à votre application.
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Créer la configuration d’Auth0" stepNumber={5}>
    Ajoutez le code du client Auth0 dans `src/lib/auth0.ts` :

    ```typescript src/lib/auth0.ts lines theme={null}
    import { Auth0Client } from '@auth0/nextjs-auth0/server';

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

  <Step title="Ajouter un proxy" stepNumber={6}>
    Ajoutez le code du proxy dans `src/proxy.ts` :

    ```typescript src/proxy.ts expandable lines theme={null}
    import { auth0 } from "./lib/auth0";

    export async function proxy(request: Request) {
      return await auth0.middleware(request);
    }

    export const config = {
      matcher: [
        /*
         * Correspond à tous les chemins de requête sauf ceux commençant par :
         * - _next/static (fichiers statiques)
         * - _next/image (fichiers d'optimisation d'images)
         * - favicon.ico, sitemap.xml, robots.txt (fichiers de métadonnées)
         */
        "/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt).*)",
      ],
    };
    ```

    <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
      Comme nous utilisons un répertoire `src/`, le fichier `proxy.ts` est créé dans `src/`. Si vous n’utilisez pas de répertoire `src/`, créez-le plutôt à la racine du projet.
    </Callout>

    <Info>
      Ce proxy configure automatiquement les routes d’authentification suivantes :

      * `/auth/login` - Route de connexion
      * `/auth/logout` - Route de déconnexion
      * `/auth/callback` - Route de rappel
      * `/auth/profile` - Route du profil utilisateur
      * `/auth/access-token` - Route du jeton d’accès
      * `/auth/backchannel-logout` - Route de déconnexion par canal arrière
    </Info>
  </Step>

  <Step title="Créer les composants Login, Logout et Profile" stepNumber={7}>
    Ajoutez le code des composants dans les fichiers créés à l’étape 3 :

    <AuthCodeGroup>
      ```typescript src/components/LoginButton.tsx lines theme={null}
      "use client";

      export default function LoginButton() {
        return (
          <a
            href="/auth/login"
            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"
          >
            Se connecter
          </a>
        );
      }
      ```

      ```typescript src/components/LogoutButton.tsx lines theme={null}
      "use client";

      export default function LogoutButton() {
        return (
          <a
            href="/auth/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"
          >
            Se déconnecter
          </a>
        );
      }
      ```

      ```typescript src/components/Profile.tsx lines theme={null}
      "use client";

      import { useUser } from "@auth0/nextjs-auth0/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, isLoading } = useUser();

        if (isLoading) return <p className="text-xs text-gray-500">Chargement...</p>;
        if (!user) return null;

        return (
          <>
            <div className="flex items-center gap-2 text-green-500 text-[13px] font-medium">
              <span className="w-5 h-5 bg-green-500 rounded-full flex items-center justify-center shrink-0">
                <svg width="10" height="8" viewBox="0 0 10 8" fill="none">
                  <path d="M1 4L3.5 6.5L9 1" stroke="white" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
                </svg>
              </span>
              Authentification réussie
            </div>
            <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>
  </Step>

  <Step title="Mettez à jour votre page d’accueil" stepNumber={8}>
    Remplacez `src/app/page.tsx` par :

    ```typescript src/app/page.tsx lines theme={null}
    import { auth0 } from "@/lib/auth0";
    import LoginButton from "@/components/LoginButton";
    import LogoutButton from "@/components/LogoutButton";
    import Profile from "@/components/Profile";

    export default async function Home() {
      const session = await auth0.getSession();
      const user = session?.user;

      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>

            {user ? (
              <>
                <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 />
              </>
            ) : (
              <>
                <h1 className="text-[17px] font-bold text-gray-900 tracking-tight">Welcome to Sample0</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 />
              </>
            )}
          </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>
      );
    }
    ```
  </Step>

  <Step title="Mettre à jour la structure de la page avec Auth0Provider" stepNumber={9}>
    Mettez à jour `src/app/layout.tsx` pour charger la police Inter et entourer votre application de `Auth0Provider` :

    ```typescript src/app/layout.tsx lines theme={null}
    import { Inter } from "next/font/google";
    import type { Metadata } from "next";
    import { Auth0Provider } from "@auth0/nextjs-auth0/client";
    import "./globals.css";

    const inter = Inter({
      subsets: ["latin"],
      weight: ["300", "400", "500", "600", "700"],
    });

    export const metadata: Metadata = {
      title: "Auth0 Next.js App",
      description: "Next.js app with Auth0 authentication",
    };

    export default function RootLayout({
      children,
    }: {
      children: React.ReactNode;
    }) {
      return (
        <html lang="en">
          <body className={inter.className}>
            <Auth0Provider>{children}</Auth0Provider>
          </body>
        </html>
      );
    }
    ```

    <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
      Dans la version 4, Auth0Provider est facultatif. Vous en avez seulement besoin si vous souhaitez transmettre un utilisateur initial pendant le rendu côté serveur afin qu’il soit disponible pour le hook useUser().
    </Callout>
  </Step>

  <Step title="Configurer Tailwind CSS" stepNumber={10}>
    Remplacez le contenu de `src/app/globals.css` par ce qui suit :

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

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

    <Info>
      Votre application sera accessible à [http://localhost:3000](http://localhost:3000). Le SDK Auth0 v4 configure automatiquement les routes d’authentification sous `/auth/*` (et non sous `/api/auth/*`, comme dans la v3).

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

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

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

***

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

<Accordion title="Erreur JWEDecryptionFailed">
  Si vous voyez l’erreur `JWEDecryptionFailed: decryption operation failed`, elle est causée soit par une valeur `AUTH0_SECRET` invalide, soit par un ancien témoin de session chiffré avec un secret différent.

  **Solution :**

  1. Générez un nouveau secret avec :

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

  2. Mettez à jour votre fichier `.env.local` :

  ```
  AUTH0_SECRET=<your-new-64-character-hex-string>
  ```

  3. **Supprimez les témoins de votre navigateur** pour `localhost:3000` :
     * Chrome/Edge : Appuyez sur `F12` → onglet Application → Cookies → Supprimez tous les cookies pour localhost
     * Firefox : Appuyez sur `F12` → onglet Storage → Cookies → Supprimez tous les cookies pour localhost
     * Safari : menu Develop → Show Web Inspector → onglet Storage → Cookies → Delete all

  4. Redémarrez votre serveur de développement :

  ```shellscript theme={null}
  npm run dev
  ```

  Le secret doit contenir exactement 32 octets (64 caractères hexadécimaux). Cette erreur se produit lorsque l’application tente de déchiffrer un témoin de session existant qui a été chiffré avec un secret différent.
</Accordion>

<Accordion title="Erreur 404 sur /auth/login">
  Si le clic sur login vous redirige vers une page 404, vérifiez ces problèmes courants :

  1. **Emplacement du proxy :** Assurez-vous que `src/proxy.ts` se trouve au bon endroit
  2. **Code du proxy :** Vérifiez que le proxy correspond au code de l’étape 6
  3. **Redémarrage du serveur :** Après avoir créé le fichier proxy, redémarrez le serveur de développement
  4. **Vérification des importations :** Assurez-vous que le chemin `import { auth0 } from "./lib/auth0"` est correct
</Accordion>

<Accordion title="Erreurs « Module Not Found »">
  Si vous voyez « Cannot find module '@/components/LoginButton' » ou une erreur semblable :

  1. **Vérifiez que les fichiers existent :** Assurez-vous que tous les fichiers de l’étape 3 ont été créés
  2. **Vérifiez les chemins :** Assurez-vous que les composants se trouvent dans le répertoire `src/components/`
  3. **Redémarrez TypeScript :** Appuyez sur `Cmd+Shift+P` (Mac) ou `Ctrl+Shift+P` (Windows), puis exécutez « TypeScript: Restart TS Server »
  4. **Vérifiez les importations :** Assurez-vous d’utiliser `@/components/*` (et non `~/components/*`)
</Accordion>

***

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

<Accordion title="Changements importants dans la v4">
  Ce guide de démarrage rapide utilise **Auth0 Next.js SDK v4**, qui apporte d’importants changements par rapport à la v3 :

  * **Aucun gestionnaire de route dynamique requis** - Les routes d’authentification sont montées automatiquement par le proxy
  * **Configuration simplifiée de l’application** - `new Auth0Client()` lit automatiquement les variables d’environnement
  * **Nouveaux chemins de route** - Les routes se trouvent sous `/auth/*` plutôt que sous `/api/auth/*`
  * **Proxy requis** - Toutes les fonctionnalités d’authentification passent par `proxy.ts`
  * **Utilisez des balises `<a>`** - La navigation doit utiliser `<a href="/auth/login">` plutôt que des boutons avec onClick

  ### Routes d’authentification

  Le SDK monte automatiquement ces routes via le proxy :

  | Route                      | Objectif                           |
  | -------------------------- | ---------------------------------- |
  | `/auth/login`              | Lancer la connexion                |
  | `/auth/logout`             | Déconnecter l’utilisateur          |
  | `/auth/callback`           | Traiter le callback Auth0          |
  | `/auth/profile`            | Obtenir le profil de l’utilisateur |
  | `/auth/access-token`       | Obtenir le jeton d’accès           |
  | `/auth/backchannel-logout` | Traiter la déconnexion backchannel |

  <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
    Si vous obtenez des erreurs 404 sur ces routes, assurez-vous que :

    1. Le fichier `proxy.ts` se trouve au bon endroit (à la racine du projet, ou dans `src/` si vous utilisez un répertoire `src/`)
    2. Le proxy est correctement configuré avec le motif `matcher` indiqué à l’étape 6
    3. Le serveur de développement a été redémarré après la création du fichier proxy
  </Callout>
</Accordion>

<Accordion title="Authentification côté serveur">
  Auth0 Next.js SDK v4 prend en charge les modèles App Router et Pages Router. Voici quelques modèles courants côté serveur :

  <Tabs>
    <Tab title="App Router - Composant serveur">
      ```typescript app/protected/page.tsx theme={null}
      import { auth0 } from "@/lib/auth0";
      import { redirect } from "next/navigation";

      export default async function ProtectedPage() {
        const session = await auth0.getSession();

        if (!session) {
          redirect('/auth/login');
        }

        return (
          <div>
            <h1>Protected Content</h1>
            <p>Welcome, {session.user.name}!</p>
          </div>
        );
      }
      ```
    </Tab>

    <Tab title="App Router - Route API">
      ```typescript app/api/protected/route.ts theme={null}
      import { auth0 } from "@/lib/auth0";
      import { NextResponse } from "next/server";

      export async function GET() {
        const session = await auth0.getSession();

        if (!session) {
          return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
        }

        return NextResponse.json({
          message: "This is a protected API route",
          user: session.user
        });
      }
      ```
    </Tab>

    <Tab title="Pages Router - Page">
      ```typescript pages/protected.tsx theme={null}
      import { auth0 } from "@/lib/auth0";
      import { GetServerSideProps } from "next";

      export default function ProtectedPage({ user }: { user: any }) {
        return (
          <div>
            <h1>Protected Content</h1>
            <p>Welcome, {user.name}!</p>
          </div>
        );
      }

      export const getServerSideProps: GetServerSideProps = auth0.withPageAuthRequired();
      ```
    </Tab>
  </Tabs>
</Accordion>

<Accordion title="Authentification côté client">
  Pour gérer l’état d’authentification côté client, utilisez le hook `useUser` :

  ```typescript components/UserProfile.tsx theme={null}
  "use client";

  import { useUser } from "@auth0/nextjs-auth0/client";

  export default function UserProfile() {
    const { user, error, isLoading } = useUser();

    if (isLoading) return <div>Loading...</div>;
    if (error) return <div>Error: {error.message}</div>;
    if (!user) return <div>Not logged in</div>;

    return (
      <div>
        <h2>{user.name}</h2>
        <p>{user.email}</p>
        <img src={user.picture} alt="Profile" referrerPolicy="no-referrer" />
      </div>
    );
  }
  ```
</Accordion>

<Accordion title="Protection des routes d’API">
  Pour protéger les routes d’API, utilisez la méthode `withApiAuthRequired` :

  ```typescript app/api/protected/route.ts theme={null}
  import { auth0 } from "@/lib/auth0";

  export const GET = auth0.withApiAuthRequired(async function handler() {
    const session = await auth0.getSession();

    return Response.json({
      message: "This is a protected API route",
      user: session?.user
    });
  });
  ```
</Accordion>

<Accordion title="Utilisation des jetons Auth0 avec des backends tiers">
  Si vous utilisez un service backend tiers (comme Convex, Supabase ou Firebase) qui exige des jetons d’authentification Auth0, vous devrez transmettre le jeton d’accès de votre application Next.js au client backend.

  ### Obtention du jeton d’accès

  **Côté serveur (App Router) :**

  ```typescript app/api/token/route.ts theme={null}
  import { auth0 } from "@/lib/auth0";
  import { NextResponse } from "next/server";

  export async function GET() {
    const session = await auth0.getSession();

    if (!session) {
      return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
    }

    const accessToken = session.accessToken;
    return NextResponse.json({ accessToken });
  }
  ```

  **Côté client :**

  ```typescript lib/convex-client.ts theme={null}
  "use client";

  import { ConvexProviderWithAuth0 } from "convex/react-auth0";
  import { ConvexReactClient } from "convex/react";

  const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL!);

  export function ConvexClientProvider({ children }: { children: React.ReactNode }) {
    return (
      <ConvexProviderWithAuth0
        client={convex}
        useAuth0={() => ({
          // Récupérer le jeton d’accès depuis votre route d’API Next.js
          getAccessToken: async () => {
            const response = await fetch("/api/token");
            const { accessToken } = await response.json();
            return accessToken;
          },
        })}
      >
        {children}
      </ConvexProviderWithAuth0>
    );
  }
  ```

  ### Configuration de votre backend

  La plupart des services tiers ont besoin de votre Domaine Auth0 et de votre audience pour vérifier les jetons. Dans la configuration de votre backend :

  ```typescript convex/auth.config.ts theme={null}
  export default {
    providers: [
      {
        domain: process.env.AUTH0_DOMAIN,
        applicationID: process.env.AUTH0_CLIENT_ID,
      },
    ],
  };
  ```

  <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
    Assurez-vous que votre application Auth0 est configurée avec une audience d’API si votre backend l’exige. Vous pouvez la définir dans Auth0 Dashboard, sous Applications → APIs, ou ajouter `AUTH0_AUDIENCE` à votre fichier `.env.local` et configurer le SDK en conséquence.
  </Callout>

  ### Résolution des problèmes liés aux jetons

  Si `ctx.auth.getUserIdentity()` renvoie `null` dans votre backend :

  1. **Vérifiez que le jeton est bien transmis :** Consultez l’onglet Réseau des outils de développement du navigateur pour confirmer que le jeton est inclus dans les requêtes
  2. **Vérifiez le format du jeton :** Assurez-vous de transmettre le `accessToken`, et non le `idToken`
  3. **Vérifiez la configuration du backend :** Confirmez que votre backend utilise le bon Domaine Auth0 et le bon ID client
  4. **Vérifiez l’audience :** Si vous utilisez une API Auth0, assurez-vous que `AUTH0_AUDIENCE` est défini et correspond à votre identifiant d’API
  5. **Inspectez les claims du jeton :** Décodez votre JWT sur [jwt.io](https://jwt.io) pour vérifier qu’il contient les claims attendues
</Accordion>
