> ## 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 montre 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 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 de [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 Angular app
  ```

  Votre assistant IA créera automatiquement votre application Auth0, récupérera les informations d’identification, installera le SDK Auth0 Angular et les plugins Capacitor, configurera les liens profonds et mettra en place les flux de connexion et de déconnexion 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 Quickstart 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éer un nouveau projet Ionic Angular avec Capacitor

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

    Ouvrir le projet

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

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

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

  <Step title="Installez le SDK Auth0 Angular et les plugins Capacitor" stepNumber={2}>
    Installez Auth0 Angular SDK ainsi que les plugins 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 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 par lien profond d’Auth0 après l’authentification

    <Info>
      Le plugin Browser de Capacitor sur iOS utilise `SFSafariViewController`, qui, sur iOS 11+, ne partage pas les cookies avec Safari. 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 façons de configurer votre application Auth0 : utiliser l'outil Quick Setup (recommandé), exécuter une commande CLI, ou configurer manuellement via le Dashboard :

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

        <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** du [Auth0 Dashboard](https://manage.auth0.com/dashboard/). Remplacez `YOUR_PACKAGE_ID` par le `appId` de votre `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 dans le répertoire racine de votre projet pour créer une application Auth0 de type Native et générer un fichier d’environnement. Mettez `PACKAGE_ID` à jour si votre `capacitor.config.ts` utilise un `appId` différent :

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

          # Configurer l’application Auth0 et générer le fichier d’environnement
          auth0 qs setup --app --type native --framework ionic-angular --name "My Ionic Angular App"
          ```

          ```powershell Windows theme={null}
          # Installer Auth0 CLI (s’il n’est pas déjà installé)
          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 d’environnement
          auth0 qs setup --app --type native --framework ionic-angular --name "My Ionic Angular App"
          ```
        </CodeGroup>

        <Note>
          Cette commande va :

          1. Vérifier si vous êtes authentifié (et vous inviter à vous connecter au besoin)
          2. Créer une application Auth0 Native
          3. Générer `src/environments/environment.ts` avec votre domaine Auth0 et votre ID client
        </Note>
      </Tab>

      <Tab title="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. Saisissez un nom pour votre application (par ex. `Ionic Angular App`), sélectionnez **Native** comme type d’application, puis cliquez sur **Create**
        4. Ouvrez l’onglet **Settings** et notez les valeurs de **Domain** et de **Client ID**
        5. Remplacez `YOUR_AUTH0_APP_DOMAIN` et `YOUR_AUTH0_APP_CLIENT_ID` dans `src/environments/environment.ts` par vos valeurs

        <Info>
          Dans ce Quickstart, `YOUR_PACKAGE_ID` correspond au champ `appId` de votre fichier `capacitor.config.ts`. La valeur par défaut est `io.ionic.starter`. Consultez le [schema 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 véritable ID de package) :

        **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** sont 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, la connexion échouera.

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

          **Allowed Origins** sont requises 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 votre 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 sont donc utilisés pour renouveler les sessions.
    * `useRefreshTokensFallback: false` — **requis** sur mobile. Empêche le SDK de recourir à une solution de secours avec l’authentification silencieuse basée sur des iframes, qui n’est pas prise en charge 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 avoir fermé puis rouvert l’application, vous pouvez 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). De plus, `localstorage` doit être considéré comme **transitoire** dans les applications Capacitor. Veuillez consulter les [recommandations sur le stockage dans la documentation de 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 Profil" 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 callbacks 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>Home</ion-title>
              </ion-toolbar>
            </ion-header>

            <ion-content class="ion-padding">
              @if (auth.isAuthenticated$ | async) {
                <ion-card>
                  <ion-card-header>
                    <ion-card-title>Welcome!</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>Get Started</ion-card-title>
                  </ion-card-header>
                  <ion-card-content>
                    <p>Sign in to your account to get started.</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>
      Le callback de l’événement `appUrlOpen` dans le composant App est encapsulé dans `this.ngZone.run()`. C’est **obligatoire**, parce que les callbacks du plugin Capacitor s’exécutent à l’extérieur de la zone d’Angular et que, 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}>
    Commencez par tester dans le navigateur :

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

    <Warning>
      Si vous exécutez l’application dans le navigateur avec `ionic serve`, la redirection au moyen d’un schéma d’URL personnalisé ne fonctionnera pas, car les navigateurs ne peuvent pas gérer ce type de schéma. Pour faire des tests dans le navigateur, remplacez temporairement `redirect_uri` par `http://localhost:8100` dans `src/main.ts` et 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 générer l’application pour le mode natif.
    </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 exécuter. Cette étape n’est nécessaire qu’une seule fois par plateforme. Assurez-vous d’avoir enregistré votre schéma d’URL personnalisé (voir Utilisation avancée ci-dessous).
    </Info>
  </Step>
</Steps>

<Check>
  **Vérification**

  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="Utiliser l’approche NgModule traditionnelle">
  Si vous avez créé votre projet avec `--type=angular` (plutôt que `--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 gabarits au lieu de la syntaxe de contrôle de flux `@if`. Les composants doivent être déclarés dans le module plutôt qu’être marqués 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 `intent-filter` à `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 l’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="Protéger les routes avec AuthGuard">
  Utilisez le garde 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',
    },
  ];
  ```

  Lorsque des utilisateurs non authentifiés tentent d’accéder à une route protégée, `authGuardFn` les redirige automatiquement vers la page de connexion Auth0.
</Accordion>

<Accordion title="Appeler des 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 du `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 : l’URL de rappel ne correspond pas

  **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 `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()`. Sans cela, 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. Allez dans Auth0 Dashboard > Applications > Votre application
  2. Remplacez le **Type d’application** par **Native**
  3. Définissez **Méthode d’authentification du point de terminaison du jeton** sur `None`
  4. Enregistrez les modifications et réessayez

  ### SSO ne fonctionne pas sur iOS

  Le plugin Browser de Capacitor utilise `SFSafariViewController`, qui ne partage pas les cookies 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 enregistrer les jetons entre les redémarrages de l’application. Soyez conscient des [implications sur la sécurité](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options) et des [limitations du 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 de `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 enchaîné à la fin.
</Accordion>

<div id="next-steps">
  ## Prochaines étapes
</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 Auth0
* [Documentation de l’Auth0 Angular SDK](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 tenant Auth0 ainsi que vos applications
* [Auth0 Marketplace](https://marketplace.auth0.com/) — Découvrez les intégrations que vous pouvez activer pour étendre les fonctionnalités d’Auth0
