> ## 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 Angular avec Capacitor

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

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 automatiquement l’authentification Auth0 en quelques minutes à l’aide des [agent skills](https://agentskills.io/home).

  Commencez par installer les agent skills Auth0 :

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

  Ensuite, demandez à votre assistant IA :

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

  Votre assistant IA créera automatiquement votre application Auth0, récupérera les identifiants, installera le SDK Angular d’Auth0 et les plugins Capacitor, configurera le deep linking et mettra en place les flux de connexion et de déconnexion avec l’intégration du navigateur natif. Pour en savoir plus, consultez les [agent skills 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 Angular avec Capacitor. Vous créerez une application adaptée aux appareils mobiles avec des fonctionnalités de connexion, de déconnexion et de profil utilisateur à l’aide du SDK Auth0 Angular et des plugins de navigateur natifs de Capacitor.

export const localEnvSnippet = `export const environment = {
  production: false,
  auth0: {
    domain: {yourDomain},
    clientId: {yourClientId}
  }
};`;

<Steps>
  <Step title="Créer un nouveau projet" stepNumber={1}>
    Créez un projet Ionic Angular avec Capacitor

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

    Ouvrez le projet

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

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

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

  <Step title="Installez le SDK Angular d’Auth0 et les plugins Capacitor" stepNumber={2}>
    Installez le SDK Angular d’Auth0 ainsi que les plugiciels Browser et App de Capacitor :

    ```shellscript theme={null}
    npm install @auth0/auth0-angular @capacitor/browser @capacitor/app
    ```

    * [`@capacitor/browser`](https://capacitorjs.com/docs/apis/browser) - ouvre la page de connexion d’Auth0 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 de lien profond d’Auth0 après l’authentification

    <Info>
      Sur iOS, le plugin Browser de Capacitor utilise `SFSafariViewController`, qui, à partir d’iOS 11, ne partage pas les cookies avec Safari. Cela signifie que [l’authentification unique (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, créez une nouvelle application sur votre locataire Auth0 et ajoutez 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 Auth0 Dashboard :

    <Tabs>
      <Tab title="Configuration rapide (recommandée)">
        Créez une application native Auth0 et copiez le fichier d’environnement prérempli avec les valeurs de configuration appropriées.

        <CreateInteractiveApp placeholderText="Ionic Angular" appType="native" allowedOriginUrls={["capacitor://localhost", "http://localhost"]} />

        <AuthCodeBlock children={localEnvSnippet} language="typescript" filename="src/environments/environment.ts" />

        Après avoir créé votre application, mettez à jour les **Allowed Callback URLs** et les **Allowed Logout URLs** dans l’onglet **Settings** de l’[Auth0 Dashboard](https://manage.auth0.com/dashboard/). Remplacez `YOUR_PACKAGE_ID` par la valeur de `appId` dans votre fichier `capacitor.config.ts` (par défaut : `io.ionic.starter`) :

        **Allowed Callback URLs** et **Allowed Logout URLs** :

        ```text theme={null}
        YOUR_PACKAGE_ID://{yourDomain}/capacitor/YOUR_PACKAGE_ID/callback
        ```
      </Tab>

      <Tab title="CLI">
        Exécutez la commande suivante à la racine de votre projet pour créer une application native Auth0 et générer un fichier d'environnement. Mettez à jour `PACKAGE_ID` si votre `capacitor.config.ts` utilise un `appId` différent :

        <AuthCodeGroup>
          ```shellscript Mac theme={null}
          AUTH0_APP_NAME="My Ionic Angular App" && PACKAGE_ID="io.ionic.starter" && brew tap auth0/auth0-cli && brew install auth0 && auth0 login --no-input && DOMAIN=$(auth0 tenants list --json | jq -r '.[] | select(.active == true) | .name') && CALLBACK_URL="${PACKAGE_ID}://${DOMAIN}/capacitor/${PACKAGE_ID}/callback" && auth0 apps create -n "${AUTH0_APP_NAME}" -t native -c "${CALLBACK_URL}" -l "${CALLBACK_URL}" -o "capacitor://localhost,http://localhost" --json --metadata created_by="quickstart-docs-cli" > auth0-app-details.json && CLIENT_ID=$(jq -r '.client_id' auth0-app-details.json) && mkdir -p src/environments && echo "export const environment = { production: false, auth0: { domain: '${DOMAIN}', clientId: '${CLIENT_ID}' } };" > src/environments/environment.ts && rm auth0-app-details.json && echo "Environment file created at src/environments/environment.ts with your Auth0 details:" && cat src/environments/environment.ts
          ```

          ```shellscript Windows theme={null}
          $AppName = "My Ionic Angular App"; $PackageId = "io.ionic.starter"; winget install Auth0.CLI; auth0 login --no-input; $Domain = (auth0 tenants list --json | ConvertFrom-Json | Where-Object { $_.active -eq $true }).name; $CallbackUrl = "${PackageId}://${Domain}/capacitor/${PackageId}/callback"; auth0 apps create -n "$AppName" -t native -c "$CallbackUrl" -l "$CallbackUrl" -o "capacitor://localhost,http://localhost" --json --metadata created_by="quickstart-docs-cli" | Set-Content -Path auth0-app-details.json; $ClientId = (Get-Content -Raw auth0-app-details.json | ConvertFrom-Json).client_id; New-Item -ItemType Directory -Force -Path "src\environments"; Set-Content -Path "src\environments\environment.ts" -Value "export const environment = { production: false, auth0: { domain: '$Domain', clientId: '$ClientId' } };"; Remove-Item auth0-app-details.json; Write-Output "Environment file created at src\environments\environment.ts with your Auth0 details:"; Get-Content "src\environments\environment.ts"
          ```
        </AuthCodeGroup>
      </Tab>

      <Tab title="Auth0 Dashboard">
        Avant de commencer, créez un fichier d’environnement dans votre projet

        ```typescript src/environments/environment.ts lines theme={null}
        export const environment = {
          production: false,
          auth0: {
            domain: 'YOUR_AUTH0_APP_DOMAIN',
            clientId: 'YOUR_AUTH0_APP_CLIENT_ID'
          }
        };
        ```

        1. Accédez au [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
        2. Cliquez sur **Applications** > **Applications** > **Create Application**
        3. Entrez un nom pour votre application (par exemple, `Ionic Angular App`), sélectionnez **Native** comme type d’application, puis cliquez sur **Create**
        4. Passez à l’onglet **Settings** et notez les valeurs de votre **Domaine** et de votre **ID client**
        5. Remplacez `YOUR_AUTH0_APP_DOMAIN` et `YOUR_AUTH0_APP_CLIENT_ID` dans `src/environments/environment.ts` par vos valeurs

        <Info>
          Tout au long de ce guide de démarrage rapide, `YOUR_PACKAGE_ID` fait référence au champ `appId` de votre `capacitor.config.ts`. La valeur par défaut est `io.ionic.starter`. Consultez le [schéma de configuration de Capacitor](https://capacitorjs.com/docs/config#schema) pour en savoir plus.
        </Info>

        Configurez les URL suivantes dans l’onglet **Settings** (remplacez `YOUR_PACKAGE_ID` par votre identifiant de package réel) :

        **Allowed Callback URLs:**

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

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

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

        **Origines autorisées :**

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

        <Info>
          **Allowed Callback URLs** constitue une mesure de sécurité essentielle pour garantir que les utilisateurs sont redirigés de façon sécuritaire vers votre application après l’authentification. Sans URL correspondante, le processus de connexion échouera.

          **Allowed Logout URLs** est essentiel pour offrir une expérience utilisateur fluide lors de la déconnexion. Sans URL correspondante, les utilisateurs recevront une erreur au moment de se déconnecter.

          **Allowed Origins** est requis pour l’authentification silencieuse. L’origine `capacitor://localhost` est utilisée pour iOS et `http://localhost` pour Android.
        </Info>
      </Tab>
    </Tabs>
  </Step>

  <Step title="Configurer le module Auth0" stepNumber={4}>
    Une fois le fichier d’environnement créé à l’étape précédente, configurez le module Auth0 dans votre application :

    ```typescript src/main.ts {4-6,10,17-25} lines theme={null}
    import { bootstrapApplication } from '@angular/platform-browser';
    import { RouteReuseStrategy, provideRouter } from '@angular/router';
    import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone';
    import { provideAuth0 } from '@auth0/auth0-angular';
    import { environment } from './environments/environment';
    import config from '../capacitor.config';
    import { routes } from './app/app.routes';
    import { AppComponent } from './app/app.component';

    const redirect_uri = `${config.appId}://${environment.auth0.domain}/capacitor/${config.appId}/callback`;

    bootstrapApplication(AppComponent, {
      providers: [
        { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
        provideIonicAngular(),
        provideRouter(routes),
        provideAuth0({
          domain: environment.auth0.domain,
          clientId: environment.auth0.clientId,
          useRefreshTokens: true,
          useRefreshTokensFallback: false,
          authorizationParams: {
            redirect_uri,
          },
        }),
      ],
    });
    ```

    La configuration `provideAuth0` comprend :

    * `useRefreshTokens: true` — **requis** sur mobile. Les applications Capacitor ne peuvent pas utiliser l’authentification silencieuse basée sur des iframes; des jetons d’actualisation servent donc à renouveler les sessions.
    * `useRefreshTokensFallback: false` — **requis** sur mobile. Empêche le SDK de revenir à l’authentification silencieuse basée sur des iframes, qui n’est pas offerte dans les applications natives.
    * `authorizationParams.redirect_uri` — utilise le schéma d’URL personnalisé de votre application pour y rediriger l’utilisateur après l’authentification.

    <Warning>
      Pour conserver l’authentification après la fermeture et la réouverture de l’application, il peut être utile de définir `cacheLocation` à `localstorage`, mais veuillez prendre connaissance des [risques liés au stockage de jetons dans localstorage](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options). De plus, `localstorage` doit être considéré comme **transitoire** dans les applications Capacitor. Veuillez consulter les [directives sur le stockage dans la documentation Capacitor](https://capacitorjs.com/docs/guides/storage#why-cant-i-just-use-localstorage-or-indexeddb).
    </Warning>
  </Step>

  <Step title="Créer des composants Login, Logout et Profile" stepNumber={5}>
    Créer les fichiers de composants

    <CodeGroup>
      ```shellscript Mac/Linux theme={null}
      touch src/app/login-button.component.ts && touch src/app/logout-button.component.ts && touch src/app/profile.component.ts
      ```

      ```powershell Windows theme={null}
      New-Item -ItemType File -Path src/app/login-button.component.ts
      New-Item -ItemType File -Path src/app/logout-button.component.ts
      New-Item -ItemType File -Path src/app/profile.component.ts
      ```
    </CodeGroup>

    Ajoutez le code suivant à chaque composant :

    <AuthCodeGroup>
      ```typescript src/app/login-button.component.ts expandable lines theme={null}
      import { Component, inject } from '@angular/core';
      import { AuthService } from '@auth0/auth0-angular';
      import { Browser } from '@capacitor/browser';
      import { IonButton } from '@ionic/angular/standalone';

      @Component({
        selector: 'app-login-button',
        standalone: true,
        imports: [IonButton],
        template: `<ion-button (click)="login()" expand="block">Log in</ion-button>`,
      })
      export class LoginButtonComponent {
        private auth = inject(AuthService);

        login(): void {
          this.auth
            .loginWithRedirect({
              async openUrl(url: string) {
                await Browser.open({ url, windowName: '_self' });
              },
            })
            .subscribe();
        }
      }
      ```

      ```typescript src/app/logout-button.component.ts expandable lines theme={null}
      import { Component, inject } from '@angular/core';
      import { AuthService } from '@auth0/auth0-angular';
      import { Browser } from '@capacitor/browser';
      import { IonButton } from '@ionic/angular/standalone';
      import { environment } from '../environments/environment';
      import config from '../../capacitor.config';

      const returnTo = `${config.appId}://${environment.auth0.domain}/capacitor/${config.appId}/callback`;

      @Component({
        selector: 'app-logout-button',
        standalone: true,
        imports: [IonButton],
        template: `<ion-button (click)="logout()" expand="block" color="danger">Log out</ion-button>`,
      })
      export class LogoutButtonComponent {
        private auth = inject(AuthService);

        logout(): void {
          this.auth
            .logout({
              logoutParams: { returnTo },
              async openUrl(url: string) {
                await Browser.open({ url });
              },
            })
            .subscribe();
        }
      }
      ```

      ```typescript src/app/profile.component.ts expandable lines theme={null}
      import { Component, inject } from '@angular/core';
      import { CommonModule } from '@angular/common';
      import { AuthService } from '@auth0/auth0-angular';
      import { IonAvatar, IonItem, IonLabel } from '@ionic/angular/standalone';

      @Component({
        selector: 'app-profile',
        standalone: true,
        imports: [CommonModule, IonAvatar, IonItem, IonLabel],
        template: `
          @if (auth.user$ | async; as user) {
            <ion-item lines="none">
              <ion-avatar slot="start">
                <img [src]="user.picture" [alt]="user.name" />
              </ion-avatar>
              <ion-label>
                <h2>{{ user.name }}</h2>
                <p>{{ user.email }}</p>
              </ion-label>
            </ion-item>
          }
        `,
      })
      export class ProfileComponent {
        protected auth = inject(AuthService);
      }
      ```
    </AuthCodeGroup>

    Mettez maintenant à jour le composant App pour gérer les rappels Auth0 et la page d'accueil pour utiliser vos composants :

    <Tabs>
      <Tab title="Composant de l’application">
        Remplacez le contenu de `src/app/app.component.ts` :

        ```typescript src/app/app.component.ts expandable lines theme={null}
        import { Component, OnInit, NgZone, inject } from '@angular/core';
        import { AuthService } from '@auth0/auth0-angular';
        import { mergeMap } from 'rxjs/operators';
        import { Browser } from '@capacitor/browser';
        import { App } from '@capacitor/app';
        import { IonApp, IonRouterOutlet } from '@ionic/angular/standalone';
        import { environment } from '../environments/environment';
        import config from '../../capacitor.config';

        const callbackUri = `${config.appId}://${environment.auth0.domain}/capacitor/${config.appId}/callback`;

        @Component({
          selector: 'app-root',
          standalone: true,
          imports: [IonApp, IonRouterOutlet],
          template: '<ion-app><ion-router-outlet></ion-router-outlet></ion-app>',
        })
        export class AppComponent implements OnInit {
          private auth = inject(AuthService);
          private ngZone = inject(NgZone);

          ngOnInit(): void {
            App.addListener('appUrlOpen', ({ url }) => {
              this.ngZone.run(() => {
                if (url?.startsWith(callbackUri)) {
                  if (
                    url.includes('state=') &&
                    (url.includes('error=') || url.includes('code='))
                  ) {
                    this.auth
                      .handleRedirectCallback(url)
                      .pipe(mergeMap(() => Browser.close()))
                      .subscribe();
                  } else {
                    Browser.close();
                  }
                }
              });
            });
          }
        }
        ```
      </Tab>

      <Tab title="Page d’accueil">
        Remplacez le contenu de `src/app/tab1/tab1.page.ts` :

        ```typescript src/app/tab1/tab1.page.ts expandable lines theme={null}
        import { Component, inject } from '@angular/core';
        import { CommonModule } from '@angular/common';
        import { AuthService } from '@auth0/auth0-angular';
        import {
          IonHeader, IonToolbar, IonTitle, IonContent,
          IonCard, IonCardHeader, IonCardTitle, IonCardContent,
        } from '@ionic/angular/standalone';
        import { LoginButtonComponent } from '../login-button.component';
        import { LogoutButtonComponent } from '../logout-button.component';
        import { ProfileComponent } from '../profile.component';

        @Component({
          selector: 'app-tab1',
          standalone: true,
          imports: [
            CommonModule,
            IonHeader, IonToolbar, IonTitle, IonContent,
            IonCard, IonCardHeader, IonCardTitle, IonCardContent,
            LoginButtonComponent, LogoutButtonComponent, ProfileComponent,
          ],
          template: `
            <ion-header>
              <ion-toolbar>
                <ion-title>Accueil</ion-title>
              </ion-toolbar>
            </ion-header>

            <ion-content class="ion-padding">
              @if (auth.isAuthenticated$ | async) {
                <ion-card>
                  <ion-card-header>
                    <ion-card-title>Bienvenue!</ion-card-title>
                  </ion-card-header>
                  <ion-card-content>
                    <app-profile />
                    <div class="ion-margin-top">
                      <app-logout-button />
                    </div>
                  </ion-card-content>
                </ion-card>
              } @else {
                <ion-card>
                  <ion-card-header>
                    <ion-card-title>Commencer</ion-card-title>
                  </ion-card-header>
                  <ion-card-content>
                    <p>Connectez-vous à votre compte pour commencer.</p>
                    <div class="ion-margin-top">
                      <app-login-button />
                    </div>
                  </ion-card-content>
                </ion-card>
              }
            </ion-content>
          `,
        })
        export class Tab1Page {
          protected auth = inject(AuthService);
        }
        ```
      </Tab>
    </Tabs>

    <Info>
      La fonction de rappel de l’événement `appUrlOpen` dans le composant App est enveloppée dans `this.ngZone.run()`. Cela est **obligatoire**, car les fonctions de rappel des plugiciels Capacitor s’exécutent en dehors de la zone d’Angular et, sans cela, Angular ne détectera pas les changements d’état d’authentification après la connexion. Consultez [Using Angular with Capacitor](https://capacitorjs.com/docs/guides/angular) pour en savoir plus.
    </Info>
  </Step>

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

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

    <Warning>
      Lorsque vous exécutez l’application dans le navigateur avec `ionic serve`, la redirection avec un schéma d’URL personnalisé ne fonctionne pas, car les navigateurs ne peuvent pas gérer 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.ts`, puis ajoutez `http://localhost:8100` aux champs **Allowed Callback URLs** et **Allowed Logout URLs** de votre application Auth0 dans l’Auth0 Dashboard. N’oubliez pas de rétablir cette valeur avant de générer la version 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, générez, 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 sur celles-ci. Cette opération n’est requise qu’une seule fois par plateforme. Assurez-vous que votre schéma URL personnalisé est enregistré (voir Utilisation avancée ci-dessous).
    </Info>
  </Step>
</Steps>

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

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

***

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

<Accordion title="Utilisation de l’approche traditionnelle avec NgModule">
  Si vous avez créé votre projet avec `--type=angular` (au lieu de `--type=angular-standalone`) ou si vous préférez utiliser des NgModules, configurez le SDK avec `AuthModule.forRoot` :

  ```typescript src/app/app.module.ts expandable lines theme={null}
  import { NgModule } from '@angular/core';
  import { BrowserModule } from '@angular/platform-browser';
  import { RouteReuseStrategy } from '@angular/router';
  import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
  import { AuthModule } from '@auth0/auth0-angular';
  import { environment } from '../environments/environment';
  import config from '../../capacitor.config';

  import { AppRoutingModule } from './app-routing.module';
  import { AppComponent } from './app.component';

  const redirect_uri = `${config.appId}://${environment.auth0.domain}/capacitor/${config.appId}/callback`;

  @NgModule({
    declarations: [AppComponent],
    imports: [
      BrowserModule,
      IonicModule.forRoot(),
      AppRoutingModule,
      AuthModule.forRoot({
        domain: environment.auth0.domain,
        clientId: environment.auth0.clientId,
        useRefreshTokens: true,
        useRefreshTokensFallback: false,
        authorizationParams: {
          redirect_uri,
        },
      }),
    ],
    providers: [{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }],
    bootstrap: [AppComponent],
  })
  export class AppModule {}
  ```

  <Note>
    Lorsque vous utilisez des NgModules, injectez `AuthService` dans le constructeur (`constructor(public auth: AuthService)`) plutôt qu’avec `inject()`. Utilisez `*ngIf="auth.user$ | async as user"` dans les modèles au lieu de la syntaxe de contrôle de flux `@if`. Les composants doivent être déclarés dans le module plutôt que définis avec `standalone: true`.
  </Note>
</Accordion>

<Accordion title="Configuration d’un schéma d’URL personnalisé">
  Pour tester l’authentification sur un appareil réel, enregistrez votre schéma d’URL personnalisé pour chaque plateforme.

  ### iOS

  Enregistrez votre schéma d’URL personnalisé dans `ios/App/App/Info.plist` :

  ```xml lines theme={null}
  <key>CFBundleURLTypes</key>
  <array>
    <dict>
      <key>CFBundleURLSchemes</key>
      <array>
        <string>YOUR_PACKAGE_ID</string>
      </array>
    </dict>
  </array>
  ```

  Remplacez `YOUR_PACKAGE_ID` par votre `appId` dans `capacitor.config.ts`. Pour en savoir plus, consultez [Defining a Custom URL Scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app).

  ### Android

  Ajoutez un filtre d’intention à `android/app/src/main/AndroidManifest.xml`, à l’intérieur de la balise `<activity>` :

  ```xml lines 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="YOUR_PACKAGE_ID" />
  </intent-filter>
  ```

  Remplacez `YOUR_PACKAGE_ID` par votre `appId` dans `capacitor.config.ts`. Pour en savoir plus, consultez [Create Deep Links to App Content](https://developer.android.com/training/app-links/deep-linking).

  ### Compiler et exécuter sur un appareil

  ```shellscript theme={null}
  ionic build && npx cap sync && npx cap open ios
  ```

  Ou pour Android :

  ```shellscript theme={null}
  ionic build && npx cap sync && npx cap open android
  ```
</Accordion>

<Accordion title="Protection des routes avec AuthGuard">
  Utilisez le guard fonctionnel pour protéger les routes qui nécessitent une authentification :

  ```typescript src/app/app.routes.ts lines theme={null}
  import { Routes } from '@angular/router';
  import { authGuardFn } from '@auth0/auth0-angular';

  export const routes: Routes = [
    {
      path: 'tabs',
      loadComponent: () => import('./tabs/tabs.page').then((m) => m.TabsPage),
      children: [
        {
          path: 'tab1',
          loadComponent: () => import('./tab1/tab1.page').then((m) => m.Tab1Page),
        },
        {
          path: 'tab2',
          loadComponent: () => import('./tab2/tab2.page').then((m) => m.Tab2Page),
          canActivate: [authGuardFn],
        },
        {
          path: 'tab3',
          loadComponent: () => import('./tab3/tab3.page').then((m) => m.Tab3Page),
          canActivate: [authGuardFn],
        },
        {
          path: '',
          redirectTo: '/tabs/tab1',
          pathMatch: 'full',
        },
      ],
    },
    {
      path: '',
      redirectTo: '/tabs/tab1',
      pathMatch: 'full',
    },
  ];
  ```

  Lorsqu’un utilisateur non authentifié accède à une route protégée, `authGuardFn` le redirige automatiquement vers la page de connexion Auth0.
</Accordion>

<Accordion title="Appel d’API protégées">
  Configurez l’intercepteur HTTP pour ajouter automatiquement des jetons d’accès aux appels d’API :

  ```typescript src/main.ts expandable lines theme={null}
  import { bootstrapApplication } from '@angular/platform-browser';
  import { RouteReuseStrategy, provideRouter } from '@angular/router';
  import { IonicRouteStrategy, provideIonicAngular } from '@ionic/angular/standalone';
  import { provideHttpClient, withInterceptors } from '@angular/common/http';
  import { provideAuth0, authHttpInterceptorFn } from '@auth0/auth0-angular';
  import { environment } from './environments/environment';
  import config from '../capacitor.config';
  import { routes } from './app/app.routes';
  import { AppComponent } from './app/app.component';

  const redirect_uri = `${config.appId}://${environment.auth0.domain}/capacitor/${config.appId}/callback`;

  bootstrapApplication(AppComponent, {
    providers: [
      { provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
      provideIonicAngular(),
      provideRouter(routes),
      provideAuth0({
        domain: environment.auth0.domain,
        clientId: environment.auth0.clientId,
        useRefreshTokens: true,
        useRefreshTokensFallback: false,
        authorizationParams: {
          redirect_uri,
          audience: 'YOUR_API_IDENTIFIER',
        },
        httpInterceptor: {
          allowedList: [
            'http://localhost:3001/api/*',
          ],
        },
      }),
      provideHttpClient(
        withInterceptors([authHttpInterceptorFn])
      ),
    ],
  });
  ```

  Ensuite, effectuez des appels d’API à l’aide de `HttpClient` d’Angular : l’intercepteur ajoute automatiquement le jeton Bearer :

  ```typescript src/app/api.service.ts lines theme={null}
  import { Injectable, inject } from '@angular/core';
  import { HttpClient } from '@angular/common/http';

  @Injectable({ providedIn: 'root' })
  export class ApiService {
    private http = inject(HttpClient);

    getData() {
      return this.http.get('http://localhost:3001/api/data');
    }
  }
  ```

  <Tip>
    `httpInterceptor.allowedList` détermine quels points de terminaison d’API reçoivent des jetons d’accès. Incluez le paramètre `audience` pour demander un jeton d’accès pour votre API. Remplacez `YOUR_API_IDENTIFIER` par l’identifiant indiqué dans [Auth0 Dashboard > APIs](https://manage.auth0.com/dashboard/).
  </Tip>
</Accordion>

<Accordion title="Problèmes courants et solutions">
  ### Erreur de non-correspondance de l’URL de rappel

  **Solution :** Vérifiez que l’URL de rappel dans votre Auth0 Dashboard correspond exactement à l’URL construite dans votre application. Assurez-vous que `YOUR_PACKAGE_ID` correspond au champ `appId` dans votre fichier `capacitor.config.ts`.

  ### L’écran ne se met pas à jour après la connexion

  **Solution :** Assurez-vous que la fonction de rappel de l’événement `appUrlOpen` est encapsulée dans `this.ngZone.run()`. Sinon, Angular ne détectera pas les changements d’état provenant de `handleRedirectCallback`. Consultez [Using Angular with Capacitor](https://capacitorjs.com/docs/guides/angular).

  ### Erreur « PKCE not allowed »

  **Correctif :**

  1. Accédez à Auth0 Dashboard > Applications > Your Application
  2. Définissez **Application Type** sur **Native**
  3. Définissez **Token Endpoint Authentication Method** sur `None`
  4. Enregistrez les modifications et réessayez

  ### Le SSO ne fonctionne pas sur iOS

  Le plugin Browser de Capacitor utilise `SFSafariViewController`, qui ne partage pas les témoins avec Safari sur iOS 11+. Si vous avez besoin du SSO, utilisez un plugin compatible qui utilise [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession).

  ### La connexion fonctionne, mais l’utilisateur reste non authentifié après le redémarrage de l’application

  Activez `cacheLocation: 'localstorage'` dans la configuration `provideAuth0` pour conserver les jetons d’une session à l’autre après le redémarrage de l’application. Tenez compte des [implications de sécurité](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options) et des [limitations de stockage de Capacitor](https://capacitorjs.com/docs/guides/storage#why-cant-i-just-use-localstorage-or-indexeddb).

  ### L’observable ne s’exécute jamais

  Toutes les méthodes `AuthService` renvoient des observables froids. Vous devez appeler `.subscribe()` pour qu’elles s’exécutent. Si `loginWithRedirect()` ou `logout()` semble ne rien faire, vérifiez que `.subscribe()` est bien chaîné à la fin.
</Accordion>

<div id="next-steps">
  ## Étapes suivantes
</div>

Consultez les ressources suivantes pour en savoir plus :

* [Exemple d’application](https://github.com/auth0-samples/auth0-ionic-samples/tree/main/angular) — Une application Ionic Angular complète avec intégration d’Auth0
* [Documentation du SDK Angular d’Auth0](https://github.com/auth0/auth0-angular) — Référence complète du SDK et exemples
* [Auth0 Dashboard](https://manage.auth0.com/dashboard/) — Configurez et gérez votre locataire Auth0 et vos applications
* [Auth0 Marketplace](https://marketplace.auth0.com/) — Découvrez les intégrations que vous pouvez activer pour étendre les fonctionnalités d’Auth0
