> ## 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 Ionic React avec Capacitor

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

export const HowToSchema = () => <script type="application/ld+json">
    {'{"@context":"https://schema.org","@type":"HowTo"}'}
  </script>;

export const CreateInteractiveApp = ({placeholderText = "Auth0", appType = "regular_web", allowedCallbackUrls = ["localhost:3000"], allowedLogoutUrls = ["localhost:3000"], allowedOriginUrls = ["localhost:3000"]}) => {
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [storeReady, setStoreReady] = useState(false);
  const [displayForm, setDisplayForm] = useState(true);
  useEffect(() => {
    const init = () => setStoreReady(true);
    if (window.rootStore) {
      window.rootStore.clientStore.setSelectedClient(null);
      window.rootStore.clientStore.setSelectedClientSecret(undefined);
      init();
    } else {
      window.addEventListener("adu:storeReady", init);
    }
    return () => {
      window.removeEventListener("adu:storeReady", init);
    };
  }, []);
  useEffect(() => {
    if (!storeReady) return;
    const disposer = autorun(() => {
      const rootStore = window.rootStore;
      setIsAuthenticated(rootStore.sessionStore.isAuthenticated);
    });
    return () => {
      disposer();
    };
  }, [storeReady]);
  if (!storeReady || typeof window === "undefined" || !displayForm) {
    return <></>;
  }
  const login = () => {
    const baseUrl = window.rootStore.config.apiBaseUrl;
    const returnTo = encodeURIComponent(window.location.href);
    window.location.href = `${baseUrl}/auth/user/login?returnTo=${returnTo}`;
  };
  const Card = ({className = "", children}) => {
    return <div className={`
          flex border rounded-2xl
          border-gray-950/10 dark:border-white/10
          py-3.5 px-4 gap-2
          text-sm text-gray-900 dark:text-gray-200
          ${className}
        `}>
        {children}
      </div>;
  };
  const Button = ({children, ...props}) => {
    return <button className="bg-[--button-primary] text-[--foreground-inverse] px-[1.125rem] py-1.5 rounded-lg font-medium" {...props}>
        {children}
      </button>;
  };
  const CreateApplicationForm = () => {
    const [name, setName] = useState("");
    const [isLoading, setIsLoading] = useState(false);
    const [error, setError] = useState("");
    const handleSubmit = async () => {
      if (!name.trim()) {
        setError("Le nom de l'application est requis");
        return;
      }
      setIsLoading(true);
      setError(null);
      try {
        await window.rootStore.clientStore.createClient({
          name: name.trim(),
          app_type: appType,
          callbacks: allowedCallbackUrls,
          allowed_logout_urls: allowedLogoutUrls,
          web_origins: allowedOriginUrls,
          client_metadata: {
            created_by: "quickstart-docs-app-creation-component"
          }
        });
        setDisplayForm(false);
      } catch (err) {
        console.error("Erreur lors de la création de l'application :", err);
        const errorMessage = err instanceof Error ? err.message : "Échec de la création de l'application";
        setError(errorMessage);
      } finally {
        setIsLoading(false);
      }
    };
    return <Card className="flex-col items-start p-4 gap-3.75">
        <span className="font-medium text-gray-900 dark:text-gray-200">Créer une application Auth0</span>
        <div className="w-full flex gap-2">
          <input id="app-name" name={name} className="
              w-full max-w-[448px] h-11 py-2 px-4 
              border rounded-lg border-gray-950/10 dark:border-white/10 
              text-gray-900 dark:text-gray-200
              focus:outline-none dark:focus:outline-none
            " placeholder={`Mon application ${placeholderText}`} value={name} onChange={e => setName(e.target.value)} />
          <Button onClick={handleSubmit}>{isLoading ? "Création en cours..." : "Créer"}</Button>
        </div>
        {error && <p className="text-red-500">{error}</p>}
      </Card>;
  };
  const SignInForm = () => {
    return <Card className="items-center">
        <Button onClick={login}>Se connecter</Button> <span>pour créer l'application</span>
      </Card>;
  };
  return isAuthenticated ? <CreateApplicationForm /> : <SignInForm />;
};

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

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

<HowToSchema />

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

  Commencez par installer les agent skills d’Auth0 :

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

  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 informations d’identification, installera le SDK Auth0 React et les plugins Capacitor, configurera les liens profonds et mettra en place les flux de connexion et de déconnexion avec intégration au navigateur natif. Pour en savoir plus, consultez [les agent skills d’Auth0](/fr-CA/docs/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 connexion, de déconnexion et de profil utilisateur à l’aide du SDK React d’Auth0 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éez une nouvelle application Ionic React avec Capacitor

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

    Ouvrez le projet

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

    <Warning>
      Assurez-vous d’utiliser le paquet `@ionic/cli` (et non le paquet `ionic`, désormais obsolète). Si vous voyez des erreurs concernant `--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 exécuter `npx cap init`.
    </Info>
  </Step>

  <Step title="Installez le SDK React d’Auth0 et les plugins Capacitor" stepNumber={2}>
    Le modèle de départ Ionic peut générer `react@19.0.0`, qui n’est pas compatible avec le SDK React d’Auth0. Assurez-vous d’abord d’utiliser 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 plug-ins 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 avec 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 retours par lien profond lorsque Auth0 redirige vers votre application

    <Info>
      Le plugin Browser de Capacitor sur iOS utilise `SFSafariViewController`, qui, sur iOS 11+, 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 s’appuie sur [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession).
    </Info>
  </Step>

  <Step title="Configurez votre application Auth0" stepNumber={3}>
    Ensuite, vous devez créer une nouvelle application dans votre tenant Auth0 et ajouter 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 configurer manuellement via le Dashboard.

    <Info>
      Tout au long de ce guide de démarrage rapide, `YOUR_PACKAGE_ID` correspond à l’identifiant de package de votre application. Il s’agit de la valeur du champ `appId` dans votre fichier `capacitor.config.ts` (par 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 application Auth0 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, accédez à ses **Settings** dans le [tableau de bord Auth0](https://manage.auth0.com/dashboard/) et mettez à jour les **Allowed Callback URLs** et les **Allowed Logout URLs** en remplaçant `YOUR_PACKAGE_ID` par l’ID de package réel de votre application 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 réglé sur **Native** et que la **méthode d’authentification du point de terminaison de jeton** est réglée sur **None**.
      </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

          # Créer une application native Auth0
          auth0 apps create \
            --name "Ionic React App" \
            --type native \
            --callbacks "YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/capacitor/YOUR_PACKAGE_ID/callback" \
            --logout-urls "YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/capacitor/YOUR_PACKAGE_ID/callback" \
            --origins "capacitor://localhost,http://localhost"
          ```

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

          # Créer une application native Auth0
          auth0 apps create `
            --name "Ionic React App" `
            --type native `
            --callbacks "YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/capacitor/YOUR_PACKAGE_ID/callback" `
            --logout-urls "YOUR_PACKAGE_ID://YOUR_AUTH0_DOMAIN/capacitor/YOUR_PACKAGE_ID/callback" `
            --origins "capacitor://localhost,http://localhost"
          ```
        </CodeGroup>

        <Note>
          Cette commande va :

          1. Vérifier si vous êtes déjà authentifié et vous inviter à vous connecter au besoin
          2. Créer une application native Auth0
          3. Afficher le **Domain** et le **Client ID** — copiez-les dans un fichier `.env` à la racine de votre projet
        </Note>

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

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

      <Tab title="Tableau de bord">
        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 [tableau de bord Auth0](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 des détails de l’application
        5. Remplacez `YOUR_AUTH0_APP_DOMAIN` et `YOUR_AUTH0_APP_CLIENT_ID` dans le fichier `.env` par les valeurs **Domain** et **Client ID** du tableau de bord
        6. Définissez **Token Endpoint Authentication Method** sur `None`

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

        **URL de rappel autorisées :**

        ```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>
          Les **URL de rappel autorisées** 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’authentification. Sans URL correspondante, le processus de connexion échouera et les utilisateurs seront bloqués sur une page d’erreur Auth0 au lieu d’accéder à votre application.

          Les **URL de déconnexion autorisées** sont essentielles pour offrir une expérience utilisateur fluide lors de la déconnexion. Sans URL correspondante, les utilisateurs ne seront pas redirigés vers votre application après s’être déconnectés et resteront plutôt sur une page générique d’Auth0.

          Les **origines autorisées** (`capacitor://localhost` pour iOS et `http://localhost` pour Android) sont requises pour que votre application native puisse communiquer avec l’API Auth0.
        </Info>
      </Tab>
    </Tabs>

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

  <Step title="Configurer l’Auth0Provider" stepNumber={4}>
    Ouvrez `src/main.tsx` et enveloppez le composant `App` dans `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` : Obligatoire pour Ionic sur Android et iOS. Les navigateurs mobiles bloquent les témoins tiers; le SDK utilise donc des jetons d’actualisation au lieu d’une authentification silencieuse basée sur des iframes.
    * `useRefreshTokensFallback` : Doit être défini à `false` pour empêcher le SDK de tenter une authentification silencieuse basée sur des iframes, qui n’est pas offerte sur mobile.
    * `authorizationParams.redirect_uri` : Utilise l’identifiant de votre package comme schéma d’URL personnalisé afin que le système d’exploitation puisse rediriger le rappel Auth0 vers votre application.

    <Warning>
      Pour conserver l’authentification après la fermeture et la réouverture de l’application, il peut être utile de définir `cacheLocation` sur `localstorage`, mais sachez qu’il existe [des risques à stocker des jetons dans localstorage](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options). Avec Capacitor, localstorage doit être considéré comme **transitoire** — le système d’exploitation peut l’effacer sans préavis. Consultez [les directives 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 s’appuie 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 [des 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 les gestionnaires de connexion, de déconnexion, de profil et de rappel" 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 plugiciel Browser de Capacitor pour ouvrir les pages de connexion et de déconnexion d'Auth0 dans le 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 via 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 le navigateur par défaut de l’appareil. En configurant `openUrl` pour utiliser `Browser.open`, le processus d’authentification reste dans le contexte de votre application, ce qui améliore l’expérience utilisateur.
    </Info>
  </Step>

  <Step title="Exécutez 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 du 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 faire des tests dans le navigateur, remplacez temporairement `redirect_uri` par `http://localhost:8100` dans `src/main.tsx` et ajoutez `http://localhost:8100` aux **Allowed Callback URLs** et aux **Allowed Logout URLs** de votre application Auth0 dans le tableau de bord. N’oubliez pas de rétablir ce changement avant de créer la version native.
    </Warning>

    Pour l’exécuter 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 exécuter l’application dessus. Cette opération n’est requise qu’une seule fois par plateforme. Ensuite, `npx cap sync` copie vos ressources Web compilées et met à jour les plugins natifs.
    </Info>
  </Step>
</Steps>

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

  Vous devriez maintenant disposer d’une connexion Auth0 entièrement fonctionnelle dans votre application Ionic. Sur un appareil, appuyer sur « Log in » ouvre la page de connexion universelle d’Auth0 dans le navigateur système et, 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 URI de rappel d’Auth0 fonctionnent sur les appareils, enregistrez l’identifiant 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 `<activity>` principal 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 la valeur réelle de `appId` 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="Protection des routes avec Ionic Router">
  Utilisez l’état d’authentification d’Auth0 pour protéger certaines routes dans 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 rappel 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 page de connexion d’Auth0 lorsqu’ils tentent d’accéder à une route protégée.
</Accordion>

<Accordion title="Appeler des API protégées">
  Configurez votre Auth0Provider de façon à inclure une audience d’API, puis 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>
  ```

  Ensuite, effectuez des appels authentifiés à l’API à partir de 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}>Appeler l’API protégée</IonButton>
        {result && (
          <IonText>
            <pre>{result}</pre>
          </IonText>
        )}
      </div>
    );
  };

  export default ApiCall;
  ```
</Accordion>
