> ## 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 le login à votre application Ionic React avec Capacitor

> Ce guide explique comment intégrer Auth0 à une application Ionic React avec Capacitor à l’aide du Auth0 React SDK.

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="Utiliser l’IA pour intégrer Auth0" icon="microchip-ai" iconType="solid" defaultOpen>
  Si vous utilisez un assistant IA de codage 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).

  Commencez par installer les Auth0 agent skills :

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

  Ensuite, demandez à votre assistant IA :

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

  Votre assistant IA créera automatiquement votre application Auth0, récupérera les identifiants, installera le Auth0 React SDK et les plugins Capacitor, configurera les liens profonds et mettra en place les flux de login et de logout avec l’intégration du navigateur natif. Pour en savoir plus, consultez [Auth0 agent skills](/docs/fr-ca/quickstart/agent-skills).
</Accordion>

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

Ce guide de démarrage rapide montre comment ajouter l’authentification Auth0 à une application Ionic React avec Capacitor. Vous créerez une application mobile avec des fonctionnalités de login, de logout et de profil d’utilisateur à l’aide du Auth0 React SDK et de l’intégration au navigateur natif de Capacitor.

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

<Steps>
  <Step title="Créer un nouveau projet" stepNumber={1}>
    Créer une nouvelle application Ionic React avec Capacitor

    ```shellscript theme={null}
    npx ionic start auth0-ionic-react tabs --type=react --capacitor
    ```

    Ouvrir le projet

    ```shellscript theme={null}
    cd auth0-ionic-react
    ```

    <Warning>
      Assurez-vous d’utiliser le package `@ionic/cli` (et non le package `ionic` obsolète). Si vous voyez des erreurs liées à `--npm-client` pendant la création du projet, mettez votre CLI à jour :

      ```shellscript theme={null}
      npm uninstall -g ionic
      npm i -g @ionic/cli
      ```
    </Warning>

    <Info>
      Si vous avez déjà une application Ionic React, assurez-vous que Capacitor est activé. Vous pouvez l’ajouter avec `ionic integrations enable capacitor`, puis `npx cap init`.
    </Info>
  </Step>

  <Step title="Installez le SDK React d’Auth0 et les plugins Capacitor" stepNumber={2}>
    Le template de démarrage Ionic peut générer `react@19.0.0`, qui n’est pas compatible avec l’Auth0 React SDK. Assurez-vous d’abord d’avoir une version de React prise en charge :

    ```shellscript theme={null}
    npm install react@^19.0.1 react-dom@^19.0.1
    ```

    Installez ensuite le SDK Auth0 et les plugins Capacitor :

    ```shellscript theme={null}
    npm install @auth0/auth0-react @capacitor/browser @capacitor/app && npx cap sync
    ```

    * [`@auth0/auth0-react`](https://github.com/auth0/auth0-react) : fournit des hooks et des composants React pour l’authentification Auth0
    * [`@capacitor/browser`](https://capacitorjs.com/docs/apis/browser) : ouvre la page de connexion dans le navigateur système de l’appareil ([SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) sur iOS, [Chrome Custom Tabs](https://developer.chrome.com/docs/android/custom-tabs) sur Android)
    * [`@capacitor/app`](https://capacitorjs.com/docs/apis/app) : gère les URL de rappel par lien profond lorsqu’Auth0 redirige vers votre application

    <Info>
      Le plugin Browser de Capacitor sur iOS utilise `SFSafariViewController`, qui, sur iOS 11 et versions ultérieures, ne partage pas les cookies avec Safari sur l’appareil. Cela signifie que le [SSO](https://auth0.com/docs/sso) ne fonctionnera pas sur ces appareils. Si vous avez besoin du SSO, utilisez un plugin compatible qui utilise [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession).
    </Info>
  </Step>

  <Step title="Configurez votre Auth0 App" stepNumber={3}>
    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 tableau de bord.

    <Info>
      Dans ce guide Quickstart, `YOUR_PACKAGE_ID` correspond à l’ID du package de votre application. Il s’agit du champ `appId` dans votre fichier `capacitor.config.ts` (p. ex. `io.ionic.starter`). Consultez le [schéma de configuration de Capacitor](https://capacitorjs.com/docs/config#schema) pour en savoir plus.
    </Info>

    <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="Ionic React" appType="native" allowedCallbackUrls={["YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/capacitor/YOUR_PACKAGE_ID/callback"]} allowedLogoutUrls={["YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/capacitor/YOUR_PACKAGE_ID/callback"]} allowedOriginUrls={["capacitor://localhost", "http://localhost"]} />

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

        Après avoir créé l’application, allez dans ses **Settings** dans le [Auth0 Dashboard](https://manage.auth0.com/dashboard/) et mettez à jour les **Allowed Callback URLs** et les **Allowed Logout URLs** pour remplacer `YOUR_PACKAGE_ID` par votre véritable ID de package et `YOUR_AUTH0_DOMAIN` par votre domaine Auth0 :

        ```text theme={null}
        YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/capacitor/YOUR_PACKAGE_ID/callback
        ```

        Assurez-vous également que le **Type d’application** est défini sur **Native** et que la **Méthode d’authentification du point de terminaison de jeton** est définie sur **Aucune**.
      </Tab>

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

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

          # Configurer l’application Auth0 et générer le fichier .env
          auth0 qs setup --app --type native --framework ionic-react --build-tool vite --name "My Ionic React App"
          ```

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

          # Configurer l’application Auth0 et générer le fichier .env
          auth0 qs setup --app --type native --framework ionic-react --build-tool vite --name "My Ionic React App"
          ```
        </CodeGroup>

        <Note>
          Cette commande :

          1. Vérifie si vous êtes authentifié(e) (et vous invite à vous connecter au besoin)
          2. Crée une application Auth0 Native
          3. Génère un fichier `.env` avec `VITE_AUTH0_DOMAIN` et `VITE_AUTH0_CLIENT_ID`
        </Note>

        Créez un fichier `.env` avec les valeurs affichées par l’Auth0 CLI :

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

      <Tab title="Dashboard">
        Avant de commencer, créez un fichier `.env` à la racine de votre projet

        ```shellscript .env theme={null}
        VITE_AUTH0_DOMAIN=YOUR_AUTH0_APP_DOMAIN
        VITE_AUTH0_CLIENT_ID=YOUR_AUTH0_APP_CLIENT_ID
        ```

        1. Accédez au [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
        2. Cliquez sur **Applications** > **Applications** > **Create Application**
        3. Dans la fenêtre contextuelle, saisissez un nom pour votre application, sélectionnez `Native` comme type d’application, puis cliquez sur **Create**
        4. Ouvrez l’onglet **Settings** dans la page Application Details
        5. Remplacez `YOUR_AUTH0_APP_DOMAIN` et `YOUR_AUTH0_APP_CLIENT_ID` dans le fichier `.env` par les valeurs **Domain** et **Client ID** du dashboard
        6. Réglez **Token Endpoint Authentication Method** sur `None`

        Enfin, dans l’onglet **Settings** de la page Application Details, configurez les URL suivantes (remplacez `YOUR_PACKAGE_ID` par votre `appId` dans `capacitor.config.ts`) :

        **Allowed Callback URLs:**

        ```text theme={null}
        YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/capacitor/YOUR_PACKAGE_ID/callback
        ```

        **URLs de déconnexion autorisées :**

        ```text theme={null}
        YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/capacitor/YOUR_PACKAGE_ID/callback
        ```

        **Origines autorisées :**

        ```text theme={null}
        capacitor://localhost, http://localhost
        ```

        <Info>
          **Allowed Callback URLs** constituent une mesure de sécurité essentielle pour garantir que les utilisateurs sont redirigés en toute sécurité vers votre application après l’authentication. Sans URL correspondante, le processus de login échouera et les utilisateurs verront une page d’erreur Auth0 au lieu d’accéder à votre application.

          **Allowed Logout URLs** sont essentielles pour offrir une expérience utilisateur fluide au moment 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 Origins** (`capacitor://localhost` pour iOS et `http://localhost` pour Android) sont requises pour que votre application native puisse communiquer avec l’Auth0 API.
        </Info>
      </Tab>
    </Tabs>

    <Tip>
      Assurez-vous que votre fichier `.env` existe : `cat .env` (Mac/Linux) ou `type .env` (Windows)
    </Tip>
  </Step>

  <Step title="Configurer Auth0Provider" stepNumber={4}>
    Ouvrez `src/main.tsx` et entourez le composant `App` avec `Auth0Provider`. Les paramètres propres aux appareils mobiles `useRefreshTokens` et `useRefreshTokensFallback` sont requis pour les applications Ionic sur iOS et Android.

    ```javascript src/main.tsx {5,6,12,13,14,15,16,17,18,19} lines theme={null}
    import React from 'react';
    import { createRoot } from 'react-dom/client';
    import App from './App';
    import { Auth0Provider } from '@auth0/auth0-react';

    // Doit correspondre à l'appId dans votre capacitor.config.ts
    const appId = 'io.ionic.starter';

    createRoot(document.getElementById('root')!).render(
      <React.StrictMode>
        <Auth0Provider
          domain={import.meta.env.VITE_AUTH0_DOMAIN}
          clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
          useRefreshTokens={true}
          useRefreshTokensFallback={false}
          authorizationParams={{
            redirect_uri: `${appId}://${import.meta.env.VITE_AUTH0_DOMAIN}/capacitor/${appId}/callback`
          }}
        >
          <App />
        </Auth0Provider>
      </React.StrictMode>
    );
    ```

    * `useRefreshTokens` : Requis pour Ionic sur Android et iOS. Les navigateurs mobiles bloquent les cookies tiers; le SDK utilise donc des jetons d’actualisation au lieu de l’authentification silencieuse basée sur des iframe.
    * `useRefreshTokensFallback` : Doit être `false` pour empêcher le SDK de tenter une authentification silencieuse basée sur des iframe, qui n’est pas offerte sur mobile.
    * `authorizationParams.redirect_uri` : Utilise l’ID de votre package comme schéma d’URL personnalisé afin que le système d’exploitation puisse rediriger le callback Auth0 vers votre application.

    <Warning>
      Pour conserver l’authentification après avoir fermé puis rouvert l’application, vous pouvez définir `cacheLocation` à `localstorage`, mais sachez qu’il existe [des risques liés au stockage de jetons dans localstorage](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options). Sur Capacitor, localstorage doit être considéré comme **transitoire** — le système d’exploitation peut l’effacer de façon inattendue. Consultez [les recommandations de Capacitor sur le stockage](https://capacitorjs.com/docs/guides/storage#why-cant-i-just-use-localstorage-or-indexeddb).

      Nous recommandons **de ne pas** utiliser le [Plugin Preferences de Capacitor](https://capacitorjs.com/docs/apis/preferences) pour stocker des jetons, car il repose sur `UserDefaults` (iOS) et `SharedPreferences` (Android), qui ne sont pas chiffrés et pourraient être synchronisés dans le nuage. Le SDK prend en charge les [implémentations de cache personnalisées](https://github.com/auth0/auth0-spa-js/blob/master/EXAMPLES.md#creating-a-custom-cache) si vous avez besoin d’un mécanisme de stockage plus sécuritaire et persistant.
    </Warning>
  </Step>

  <Step title="Créer un gestionnaire de Login, Logout, profil et callback" stepNumber={5}>
    Créer des fichiers

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

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

    Et ajoutez les extraits de code suivants

    <AuthCodeGroup>
      ```javascript src/LoginButton.tsx lines theme={null}
      import { useAuth0 } from '@auth0/auth0-react';
      import { Browser } from '@capacitor/browser';
      import { IonButton } from '@ionic/react';

      const LoginButton: React.FC = () => {
        const { loginWithRedirect } = useAuth0();

        const login = async () => {
          await loginWithRedirect({
            async openUrl(url) {
              await Browser.open({
                url,
                windowName: "_self"
              });
            }
          });
        };

        return <IonButton onClick={login}>Log in</IonButton>;
      };

      export default LoginButton;
      ```

      ```javascript src/LogoutButton.tsx lines theme={null}
      import { useAuth0 } from '@auth0/auth0-react';
      import { Browser } from '@capacitor/browser';
      import { IonButton } from '@ionic/react';

      const appId = 'io.ionic.starter';

      const LogoutButton: React.FC = () => {
        const { logout } = useAuth0();

        const logoutUri = `${appId}://${import.meta.env.VITE_AUTH0_DOMAIN}/capacitor/${appId}/callback`;

        const doLogout = async () => {
          await logout({
            logoutParams: {
              returnTo: logoutUri,
            },
            async openUrl(url) {
              await Browser.open({
                url,
                windowName: "_self"
              });
            }
          });
        };

        return <IonButton onClick={doLogout} color="danger">Log out</IonButton>;
      };

      export default LogoutButton;
      ```

      ```javascript src/Profile.tsx lines theme={null}
      import { useAuth0 } from '@auth0/auth0-react';
      import { IonAvatar, IonItem, IonLabel } from '@ionic/react';

      const Profile: React.FC = () => {
        const { user, isAuthenticated, isLoading } = useAuth0();

        if (isLoading) {
          return <IonItem><IonLabel>Loading profile...</IonLabel></IonItem>;
        }

        return (
          isAuthenticated && user ? (
            <IonItem lines="none">
              <IonAvatar slot="start">
                <img
                  src={user.picture || `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='50' fill='%2363b3ed'/%3E%3Cpath d='M50 45c7.5 0 13.64-6.14 13.64-13.64S57.5 17.72 50 17.72s-13.64 6.14-13.64 13.64S42.5 45 50 45zm0 6.82c-9.09 0-27.28 4.56-27.28 13.64v3.41c0 1.88 1.53 3.41 3.41 3.41h47.74c1.88 0 3.41-1.53 3.41-3.41v-3.41c0-9.08-18.19-13.64-27.28-13.64z' fill='%23fff'/%3E%3C/svg%3E`}
                  alt={user.name || 'User'}
                  onError={(e) => {
                    const target = e.target as HTMLImageElement;
                    target.src = `data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100' viewBox='0 0 100 100'%3E%3Ccircle cx='50' cy='50' r='50' fill='%2363b3ed'/%3E%3Cpath d='M50 45c7.5 0 13.64-6.14 13.64-13.64S57.5 17.72 50 17.72s-13.64 6.14-13.64 13.64S42.5 45 50 45zm0 6.82c-9.09 0-27.28 4.56-27.28 13.64v3.41c0 1.88 1.53 3.41 3.41 3.41h47.74c1.88 0 3.41-1.53 3.41-3.41v-3.41c0-9.08-18.19-13.64-27.28-13.64z' fill='%23fff'/%3E%3C/svg%3E`;
                  }}
                />
              </IonAvatar>
              <IonLabel>
                <h2>{user.name}</h2>
                <p>{user.email}</p>
              </IonLabel>
            </IonItem>
          ) : null
        );
      };

      export default Profile;
      ```

      ```javascript src/App.tsx expandable lines theme={null}
      import { useEffect } from 'react';
      import { Redirect, Route } from 'react-router-dom';
      import {
        IonApp,
        IonIcon,
        IonLabel,
        IonRouterOutlet,
        IonTabBar,
        IonTabButton,
        IonTabs,
        setupIonicReact,
      } from '@ionic/react';
      import { IonReactRouter } from '@ionic/react-router';
      import { personCircle, logIn } from 'ionicons/icons';
      import { App as CapApp } from '@capacitor/app';
      import { Browser } from '@capacitor/browser';
      import { useAuth0 } from '@auth0/auth0-react';
      import HomePage from './pages/Home';

      /* CSS Ionic */
      import '@ionic/react/css/core.css';
      import '@ionic/react/css/normalize.css';
      import '@ionic/react/css/structure.css';
      import '@ionic/react/css/typography.css';
      import '@ionic/react/css/padding.css';
      import '@ionic/react/css/float-elements.css';
      import '@ionic/react/css/text-alignment.css';
      import '@ionic/react/css/text-transformation.css';
      import '@ionic/react/css/flex-utils.css';
      import '@ionic/react/css/display.css';

      setupIonicReact();

      const App: React.FC = () => {
        const { handleRedirectCallback } = useAuth0();

        useEffect(() => {
          CapApp.addListener('appUrlOpen', async ({ url }) => {
            if (url.includes('state') && (url.includes('code') || url.includes('error'))) {
              await handleRedirectCallback(url);
            }
            await Browser.close();
          });
        }, [handleRedirectCallback]);

        return (
          <IonApp>
            <IonReactRouter>
              <IonTabs>
                <IonRouterOutlet>
                  <Route exact path="/home">
                    <HomePage />
                  </Route>
                  <Route exact path="/">
                    <Redirect to="/home" />
                  </Route>
                </IonRouterOutlet>
                <IonTabBar slot="bottom">
                  <IonTabButton tab="home" href="/home">
                    <IonIcon aria-hidden="true" icon={personCircle} />
                    <IonLabel>Home</IonLabel>
                  </IonTabButton>
                </IonTabBar>
              </IonTabs>
            </IonReactRouter>
          </IonApp>
        );
      };

      export default App;
      ```

      ```javascript src/pages/Home.tsx expandable lines theme={null}
      import {
        IonContent,
        IonHeader,
        IonPage,
        IonTitle,
        IonToolbar,
      } from '@ionic/react';
      import { useAuth0 } from '@auth0/auth0-react';
      import LoginButton from '../LoginButton';
      import LogoutButton from '../LogoutButton';
      import Profile from '../Profile';

      const HomePage: React.FC = () => {
        const { isAuthenticated, isLoading, error } = useAuth0();

        return (
          <IonPage>
            <IonHeader>
              <IonToolbar>
                <IonTitle>Auth0 + Ionic React</IonTitle>
              </IonToolbar>
            </IonHeader>
            <IonContent className="ion-padding" fullscreen>
              {isLoading && <p>Loading...</p>}

              {error && <p>Error: {error.message}</p>}

              {!isLoading && !isAuthenticated && (
                <div className="ion-text-center ion-padding-top">
                  <h2>Welcome</h2>
                  <p>Sign in to get started</p>
                  <LoginButton />
                </div>
              )}

              {!isLoading && isAuthenticated && (
                <div className="ion-padding-top">
                  <Profile />
                  <div className="ion-text-center ion-padding-top">
                    <LogoutButton />
                  </div>
                </div>
              )}
            </IonContent>
          </IonPage>
        );
      };

      export default HomePage;
      ```
    </AuthCodeGroup>

    Le rappel `openUrl` dans `LoginButton` et `LogoutButton` utilise le plugin Browser de Capacitor pour ouvrir les pages de login et de logout Auth0 dans le composant de navigateur système de l’appareil, plutôt que de quitter complètement l’application.

    Le composant `App` écoute l’événement `appUrlOpen`, qui se déclenche lorsqu’Auth0 redirige vers votre application en utilisant le schéma d’URL personnalisé. Il appelle `handleRedirectCallback` pour échanger le code d’autorisation contre des jetons, puis ferme le navigateur.

    <Info>
      Par défaut, la méthode `loginWithRedirect` du SDK utilise `window.location.href` pour rediriger vers la page de connexion, ce qui ouvre l’application de navigateur par défaut de l’appareil. En configurant `openUrl` pour utiliser `Browser.open`, vous gardez le flux d’authentification dans le contexte de votre application, pour une meilleure expérience utilisateur.
    </Info>
  </Step>

  <Step title="Lancez votre application" stepNumber={6}>
    Testez d’abord dans le navigateur

    ```shellscript theme={null}
    ionic serve
    ```

    <Warning>
      Lors de l’exécution dans le navigateur avec `ionic serve`, la redirection par schéma d’URL personnalisé (`io.ionic.starter://...`) ne fonctionnera pas, car les navigateurs ne prennent pas en charge les schémas d’URL personnalisés. Pour effectuer des tests dans le navigateur, remplacez temporairement `redirect_uri` par `http://localhost:8100` dans `src/main.tsx`, puis ajoutez `http://localhost:8100` à **Allowed Callback URLs** et à **Allowed Logout URLs** de votre application Auth0 dans le Dashboard. N’oubliez pas de rétablir cette modification avant de compiler pour Native.
    </Warning>

    Pour exécuter l’application sur un appareil ou un simulateur, ajoutez d’abord les plateformes natives :

    ```shellscript theme={null}
    npx cap add ios
    npx cap add android
    ```

    Ensuite, compilez, synchronisez et exécutez :

    <CodeGroup>
      ```shellscript iOS theme={null}
      ionic build && npx cap sync && npx cap run ios
      ```

      ```shellscript Android theme={null}
      ionic build && npx cap sync && npx cap run android
      ```
    </CodeGroup>

    <Info>
      Vous devez ajouter les plateformes natives avec `npx cap add` avant de pouvoir les lancer. Cette étape ne doit être effectuée qu’une seule fois par plateforme. Ensuite, `npx cap sync` copie vos assets Web compilés et met à jour les plug-ins natifs.
    </Info>
  </Step>
</Steps>

<Check>
  **Checkpoint**

  Vous devriez maintenant avoir un login Auth0 entièrement fonctionnel dans votre application Ionic. Sur un appareil, un appui sur « Se connecter » ouvre la page de connexion Universal Login d’Auth0 dans le navigateur système, puis, après l’authentification, vous êtes redirigé vers votre application, où le profil de l’utilisateur s’affiche.
</Check>

***

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

<Accordion title="Configuration d’un schéma d’URL personnalisé (iOS et Android)">
  Pour que les callbacks Auth0 fonctionnent sur les appareils, enregistrez l’ID de votre package comme schéma d’URL personnalisé sur chaque plateforme.

  **iOS** — ajoutez ceci à `ios/App/App/Info.plist` :

  ```xml ios/App/App/Info.plist theme={null}
  <key>CFBundleURLTypes</key>
  <array>
    <dict>
      <key>CFBundleURLSchemes</key>
      <array>
        <string>io.ionic.starter</string>
      </array>
    </dict>
  </array>
  ```

  **Android** — ajoutez un `intent-filter` dans l’élément principal `<activity>` de `android/app/src/main/AndroidManifest.xml` :

  ```xml android/app/src/main/AndroidManifest.xml theme={null}
  <intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="io.ionic.starter" />
  </intent-filter>
  ```

  Remplacez `io.ionic.starter` par votre `appId` réel dans `capacitor.config.ts`.

  <Info>
    Pour en savoir plus, consultez [Defining a Custom URL Scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app) pour iOS, ou [Create Deep Links to App Content](https://developer.android.com/training/app-links/deep-linking) pour Android.
  </Info>
</Accordion>

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

  ```jsx src/App.tsx theme={null}
  import { useAuth0, withAuthenticationRequired } from '@auth0/auth0-react';
  import { IonReactRouter } from '@ionic/react-router';
  import { IonRouterOutlet } from '@ionic/react';
  import { Route, Redirect } from 'react-router-dom';
  import HomePage from './pages/Home';
  import DashboardPage from './pages/Dashboard';

  const ProtectedRoute = ({ component, ...args }: any) => {
    const Component = withAuthenticationRequired(component, {
      onRedirecting: () => <div className="ion-padding">Loading...</div>,
    });
    return <Route {...args} render={() => <Component />} />;
  };

  const App: React.FC = () => {
    // ... gestionnaire de callback de l’étape précédente

    return (
      <IonApp>
        <IonReactRouter>
          <IonRouterOutlet>
            <Route exact path="/home" component={HomePage} />
            <ProtectedRoute exact path="/dashboard" component={DashboardPage} />
            <Route exact path="/">
              <Redirect to="/home" />
            </Route>
          </IonRouterOutlet>
        </IonReactRouter>
      </IonApp>
    );
  };
  ```

  Le HOC `withAuthenticationRequired` redirige automatiquement les utilisateurs non authentifiés vers la Auth0 login page lorsqu’ils essaient d’accéder à une route protégée.
</Accordion>

<Accordion title="Appeler des API protégées">
  Configurez votre Auth0Provider pour inclure une audience d’API et utilisez la méthode `getAccessTokenSilently` pour obtenir des jetons d’accès pour votre backend :

  ```jsx src/main.tsx theme={null}
  <Auth0Provider
    domain={import.meta.env.VITE_AUTH0_DOMAIN}
    clientId={import.meta.env.VITE_AUTH0_CLIENT_ID}
    useRefreshTokens={true}
    useRefreshTokensFallback={false}
    authorizationParams={{
      redirect_uri: `${appId}://${import.meta.env.VITE_AUTH0_DOMAIN}/capacitor/${appId}/callback`,
      audience: "YOUR_API_IDENTIFIER"
    }}
  >
    <App />
  </Auth0Provider>
  ```

  Faites ensuite des appels d’API authentifiés depuis vos composants :

  ```jsx src/ApiCall.tsx theme={null}
  import { useState } from 'react';
  import { useAuth0 } from '@auth0/auth0-react';
  import { IonButton, IonText } from '@ionic/react';

  const ApiCall: React.FC = () => {
    const { getAccessTokenSilently } = useAuth0();
    const [result, setResult] = useState<string | null>(null);

    const callApi = async () => {
      try {
        const token = await getAccessTokenSilently();

        const response = await fetch('https://your-api.example.com/protected', {
          headers: {
            Authorization: `Bearer ${token}`
          }
        });

        const data = await response.json();
        setResult(JSON.stringify(data, null, 2));
      } catch (error) {
        console.error('API call failed:', error);
      }
    };

    return (
      <div className="ion-padding">
        <IonButton onClick={callApi}>Call Protected API</IonButton>
        {result && (
          <IonText>
            <pre>{result}</pre>
          </IonText>
        )}
      </div>
    );
  };

  export default ApiCall;
  ```
</Accordion>
