> ## 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 montre comment intégrer Auth0 à toute nouvelle application Next.js ou à une application 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 obligatoire");
        return;
      }
      setIsLoading(true);
      setError(null);
      try {
        await window.rootStore.clientStore.createClient({
          name: name.trim(),
          app_type: appType,
          callbacks: allowedCallbackUrls,
          allowed_logout_urls: allowedLogoutUrls,
          web_origins: allowedOriginUrls,
          client_metadata: {
            created_by: "quickstart-docs-app-creation-component"
          }
        });
        setDisplayForm(false);
      } catch (err) {
        console.error("Erreur lors de la création du client :", err);
        const errorMessage = err instanceof Error ? err.message : "Échec de la création de l'application";
        setError(errorMessage);
      } finally {
        setIsLoading(false);
      }
    };
    return <Card className="flex-col items-start p-4 gap-3.75">
        <span className="font-medium text-gray-900 dark:text-gray-200">Créer une Auth0 App</span>
        <div className="w-full flex gap-2">
          <input id="app-name" name={name} className="
              w-full max-w-[448px] h-11 py-2 px-4 
              border rounded-lg border-gray-950/10 dark:border-white/10 
              text-gray-900 dark:text-gray-200
              focus:outline-none dark:focus:outline-none
            " placeholder={`Mon application ${placeholderText}`} value={name} onChange={e => setName(e.target.value)} />
          <Button onClick={handleSubmit}>{isLoading ? "Création en cours..." : "Créer"}</Button>
        </div>
        {error && <p className="text-red-500">{error}</p>}
      </Card>;
  };
  const SignInForm = () => {
    return <Card className="items-center">
        <Button onClick={login}>Se connecter</Button> <span>pour créer l'application</span>
      </Card>;
  };
  return isAuthenticated ? <CreateApplicationForm /> : <SignInForm />;
};

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

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

<HowToSchema />

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

  **Installation :**

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

  **Ensuite, demandez à 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 des routes d’API et configurera les variables d’environnement. [Documentation complète sur Agent Skills →](/docs/fr-ca/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 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`
</Callout>

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

Ce guide de démarrage rapide montre comment ajouter l’authentification Auth0 à une application Next.js 16. Vous créerez une application web full stack avec rendu côté serveur, une fonctionnalité de connexion sécurisée et des routes protégées à l’aide du SDK Auth0 Next.js.

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 Quickstart

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

    Ouvrir le projet

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

  <Step title="Installer le SDK Auth0 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 Auth0 App" stepNumber={4}>
    Ensuite, vous devez créer une nouvelle application sur votre tenant 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 configurer manuellement via le Dashboard :

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

        <CreateInteractiveApp placeholderText="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 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}
          # Installez Auth0 CLI (si ce n’est pas déjà fait)
          brew tap auth0/auth0-cli && brew install auth0

          # Configurez l’Auth0 App 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’Auth0 App 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é(e) (et demander de vous connecter au besoin)
          2. Créer une Auth0 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="Dashboard">
        Créez un fichier `.env.local` dans le répertoire 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 une valeur AUTH0\_SECRET sécurisée :**

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

        Copiez le résultat et remplacez `YOUR_LONG_RANDOM_SECRET_HERE` dans `.env.local`. Cette valeur doit contenir 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 contextuelle, entrez un nom pour votre application, sélectionnez `Regular Web Application` comme type d’application, puis cliquez sur **Create**
        4. Ouvrez l’onglet **Settings** sur la page Application Details
        5. Remplacez `YOUR_AUTH0_APP_DOMAIN`, `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 Dashboard

        <Warning>
          **Critique :** Si vous modifiez `AUTH0_SECRET` après le démarrage de l’application, vous devez supprimer les cookies de votre navigateur pour localhost. Les anciens session cookies chiffrés avec le secret précédent provoqueront une erreur `JWEDecryptionFailed`.
        </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>
          **Allowed Callback URLs** constitue une mesure de sécurité essentielle pour s’assurer que les utilisateurs sont redirigés de façon sécuritaire vers votre application après l’authentication. Sans URL correspondante, le login process é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 user experience fluide lors de la déconnexion. Sans URL correspondante, les utilisateurs ne seront pas redirigés vers votre application après le logout et resteront plutôt sur une page Auth0 générique.

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

  <Step title="Cré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 des composants de connexion, de déconnexion et de profil" stepNumber={7}>
    Ajoutez le code des composants aux 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"
          >
            Connexion
          </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"
          >
            Déconnexion
          </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 le layout 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, le Auth0Provider est facultatif. Vous en avez besoin uniquement si vous voulez transmettre un utilisateur initial lors du rendu côté serveur afin qu’il soit accessible dans le hook useUser().
    </Callout>
  </Step>

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

    ```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 à l’adresse [http://localhost:3000](http://localhost:3000). L’Auth0 SDK v4 configure automatiquement les routes d’authentification sous `/auth/*` (et non `/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>
  **Vérification**

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

***

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

<Accordion title="JWEDecryptionFailed Error">
  Si vous voyez l’erreur `JWEDecryptionFailed: decryption operation failed`, c’est qu’il y a soit un `AUTH0_SECRET` invalide, soit un ancien cookie 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. **Effacez les cookies 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). L’erreur se produit lorsque l’application essaie de déchiffrer un cookie de session existant qui a été chiffré avec un secret différent.
</Accordion>

<Accordion title="Erreur 404 sur /auth/login">
  Si le fait de cliquer sur login vous mène à 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émarrer le serveur :** Après avoir créé le fichier proxy, redémarrez le serveur de développement
  4. **Vérifier les importations :** Assurez-vous que le chemin `import { auth0 } from "./lib/auth0"` est correct
</Accordion>

<Accordion title="Erreurs Module Not Found">
  Si vous voyez l’erreur "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 bien été créés
  2. **Vérifiez les chemins :** Assurez-vous que les composants se trouvent dans le répertoire `src/components/`
  3. **Redémarrer TypeScript :** Appuyez sur `Cmd+Shift+P` (Mac) ou `Ctrl+Shift+P` (Windows), puis exécutez "TypeScript: Restart TS Server"
  4. **Vérifier les importations :** Assurez-vous d’utiliser `@/components/*` (et non `~/components/*`)
</Accordion>

***

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

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

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

  ### Routes d’authentification

  Le SDK monte automatiquement ces routes par l’intermédiaire du proxy :

  | Route                      | But                              |
  | -------------------------- | -------------------------------- |
  | `/auth/login`              | Lancer la connexion              |
  | `/auth/logout`             | Déconnecter l’utilisateur        |
  | `/auth/callback`           | Traiter le callback Auth0        |
  | `/auth/profile`            | Obtenir le profil utilisateur    |
  | `/auth/access-token`       | Obtenir le jeton d’accès         |
  | `/auth/backchannel-logout` | Gérer 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` est 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 bien é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 d’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 une route 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="Utiliser 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.

  ### Obtenir le 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érez 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>
    );
  }
  ```

  ### Configurer votre backend

  La plupart des services tiers ont besoin de votre domaine Auth0 et de votre audience pour valider 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 le Auth0 Dashboard sous Applications → APIs, ou ajouter `AUTH0_AUDIENCE` à votre `.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 Network des DevTools de votre 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 l’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 attendus
</Accordion>
