> ## 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.

# Agrega Login a tu aplicación Ionic Vue con Capacitor

> Esta guía muestra cómo integrar Auth0 en una aplicación Ionic Vue y Capacitor mediante el SDK de Auth0 para Vue.

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("El nombre de la aplicación es obligatorio");
        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("Error creating client:", err);
        const errorMessage = err instanceof Error ? err.message : "No se pudo crear la aplicación";
        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">Crear aplicación de 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={`My ${placeholderText} App`} value={name} onChange={e => setName(e.target.value)} />
          <Button onClick={handleSubmit}>{isLoading ? "Creando..." : "Crear"}</Button>
        </div>
        {error && <p className="text-red-500">{error}</p>}
      </Card>;
  };
  const SignInForm = () => {
    return <Card className="items-center">
        <Button onClick={login}>Iniciar sesión</Button> <span>para crear la aplicación</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) + "*****ENMASCARADO*****";
          }
          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="Usa IA para integrar Auth0" icon="microchip-ai" iconType="solid" defaultOpen>
  Si usas un asistente de programación con IA como Claude Code, Cursor o GitHub Copilot, puedes añadir la autenticación de Auth0 automáticamente en minutos con [agent skills](https://agentskills.io/home).
  Primero, instala las agent skills de Auth0:

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

  Luego, pídele a tu asistente de IA:

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

  Tu asistente de IA creará automáticamente tu aplicación de Auth0, obtendrá las credenciales, instalará el SDK de Auth0 para Vue y los plugins de Capacitor, configurará el deep linking e implementará los flujos de inicio y cierre de sesión con integración con el navegador nativo. Obtén más información sobre las [agent skills de Auth0](/es/docs/quickstart/agent-skills).
</Accordion>

<div id="get-started">
  ## Primeros pasos
</div>

Este inicio rápido muestra cómo añadir la autenticación de Auth0 a una aplicación Ionic Vue que se ejecuta en iOS y Android con Capacitor. Crearás una aplicación móvil segura con funciones de Login, cierre de sesión y perfil de usuario mediante el SDK de Auth0 para Vue y los complementos de navegador nativos de Capacitor.

<Steps>
  <Step title="Crear un proyecto nuevo" stepNumber={1}>
    Crea un nuevo proyecto de Ionic Vue con Capacitor

    ```shellscript theme={null}
    npx ionic start auth0-ionic-vue blank --type=vue --capacitor
    ```

    Abre el proyecto

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

    <Warning>
      Asegúrate de usar el paquete `@ionic/cli` (no el paquete `ionic`, que está obsoleto). Si ves errores relacionados con `--npm-client` durante la creación del proyecto, actualiza tu CLI:

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

  <Step title="Instala el SDK de Auth0 para Vue y los complementos de Capacitor" stepNumber={2}>
    ```shellscript theme={null}
    npm install @auth0/auth0-vue @capacitor/browser @capacitor/app
    ```

    <Info>
      **[`@capacitor/browser`](https://capacitorjs.com/docs/apis/browser)** abre la página de Universal Login de Auth0 en el navegador del sistema del dispositivo (SFSafariViewController en iOS, Chrome Custom Tabs en Android) para proporcionar una autenticación segura.

      **[`@capacitor/app`](https://capacitorjs.com/docs/apis/app)** detecta eventos de enlaces profundos para que tu aplicación pueda gestionar el callback de OAuth cuando Auth0 redirige de vuelta tras el Login.
    </Info>
  </Step>

  <Step title="Configura tu aplicación de Auth0" stepNumber={3}>
    A continuación, debes crear una nueva aplicación en tu inquilino de Auth0. Las aplicaciones Ionic Capacitor usan el tipo de aplicación **Native** con callbacks de esquema de URL personalizado.

    Tienes tres opciones para configurar tu aplicación de Auth0: usar la herramienta Quick Setup (recomendado), ejecutar un comando de la CLI o configurarla manualmente en el Dashboard:

    <Tabs>
      <Tab title="Quick Setup (recomendado)">
        Crea una aplicación **Native** de Auth0 y obtén tus credenciales.

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

        Después de crear tu aplicación, anota los valores de **dominio** e **ID de cliente** para el siguiente paso.

        <Note>
          También tendrás que configurar las URL de callback y cierre de sesión en el Dashboard. Consulta la configuración de las URL a continuación.
        </Note>
      </Tab>

      <Tab title="CLI">
        Ejecuta los siguientes comandos en el directorio raíz de tu proyecto para crear una aplicación de Auth0:

        <CodeGroup>
          ```shellscript Mac theme={null}
          # Instala Auth0 CLI (si aún no está instalado)
          brew tap auth0/auth0-cli && brew install auth0

          # Inicia sesión y crea una aplicación Native
          auth0 login && auth0 apps create \
            -n "My Ionic Vue App" \
            -t native \
            -o "capacitor://localhost,http://localhost" \
            --no-input
          ```

          ```powershell Windows theme={null}
          # Instala Auth0 CLI (si aún no está instalado)
          scoop bucket add auth0 https://github.com/auth0/scoop-auth0-cli.git
          scoop install auth0

          # Inicia sesión y crea una aplicación Native
          auth0 login; auth0 apps create `
            -n "My Ionic Vue App" `
            -t native `
            -o "capacitor://localhost,http://localhost" `
            --no-input
          ```
        </CodeGroup>

        <Note>
          Este comando hará lo siguiente:

          1. Te autenticará en Auth0 (y te pedirá que inicies sesión si es necesario)
          2. Creará una aplicación **Native** con los orígenes permitidos configurados
          3. Mostrará el **dominio** y el **ID de cliente** para usarlos en tu proyecto

          Aún tendrás que configurar las URL de callback y cierre de sesión en el Dashboard. Consulta la información a continuación.
        </Note>
      </Tab>

      <Tab title="Dashboard">
        1. Ve al [Auth0 Dashboard](https://manage.auth0.com/dashboard/)
        2. Haz clic en **Applications** > **Applications** > **Create Application**
        3. Introduce un nombre para tu aplicación (por ejemplo, `Ionic Vue App`), selecciona **Native** como tipo de aplicación y haz clic en **Create**
        4. Ve a la pestaña **Settings** y anota los valores de **dominio** e **ID de cliente**

        <Info>
          A lo largo de esta guía, `YOUR_PACKAGE_ID` es el ID de paquete de tu aplicación. Puedes encontrarlo y configurarlo en el campo `appId` de tu archivo `capacitor.config.ts`. Consulta el [esquema de configuración de Capacitor](https://capacitorjs.com/docs/config#schema) para obtener más información.
        </Info>

        Configura las siguientes URL en la pestaña **Settings** de la página de detalles de tu aplicación:

        **Allowed Callback URLs:**

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

        **Allowed Logout URLs:**

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

        **Allowed Origins:**

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

        <Info>
          **Allowed Callback URLs** son una medida de seguridad fundamental para garantizar que los usuarios regresen de forma segura a tu aplicación después de autenticarse. Sin una URL coincidente, el proceso de inicio de sesión fallará y los usuarios verán una página de error de Auth0 en lugar de acceder a tu aplicación.

          **Allowed Logout URLs** son esenciales para ofrecer una experiencia fluida al cerrar sesión. Sin una URL coincidente, los usuarios no serán redirigidos de vuelta a tu aplicación después de cerrar sesión y, en su lugar, se quedarán en una página genérica de Auth0.

          **Allowed Origins** deben incluir `capacitor://localhost` (iOS) y `http://localhost` (Android) para las solicitudes de aplicaciones nativas a Auth0.
        </Info>
      </Tab>
    </Tabs>

    <Tip>
      Si usaste **Quick Setup** o **CLI**, ve a la pestaña **Settings** de tu aplicación en el [Auth0 Dashboard](https://manage.auth0.com/#/applications) para configurar las URL de callback y cierre de sesión que se muestran en la pestaña Dashboard anterior.
    </Tip>
  </Step>

  <Step title="Configura el plugin de Auth0" stepNumber={4}>
    ```typescript src/main.ts {5,6,8,9,14,15,16,17,18,19,20,21,22,23} lines theme={null}
    import { createApp } from 'vue'
    import App from './App.vue'
    import router from './router'
    import { IonicVue } from '@ionic/vue'
    import { createAuth0 } from '@auth0/auth0-vue'
    import config from '../capacitor.config'

    // Construye la URL de callback usando el ID de paquete de tu aplicación
    const redirect_uri = `${config.appId}://{yourDomain}/capacitor/${config.appId}/callback`

    const app = createApp(App)
      .use(IonicVue)
      .use(router)

    app.use(
      createAuth0({
        domain: '{yourDomain}',
        clientId: '{yourClientId}',
        useRefreshTokens: true,
        useRefreshTokensFallback: false,
        authorizationParams: {
          redirect_uri,
        },
      })
    )

    router.isReady().then(() => {
      app.mount('#app')
    })
    ```

    <Info>
      * **`useRefreshTokens: true`** — Los navegadores móviles bloquean las cookies de terceros, por lo que la autenticación silenciosa basada en `iframe` no funciona. Los Tokens de actualización usan directamente el endpoint `/oauth/token`.
      * **`useRefreshTokensFallback: false`** — Evita que el SDK intente usar la alternativa basada en `iframe`, que no está disponible en dispositivos móviles.
      * **`router.isReady().then(...)`** — Garantiza que Vue Router esté completamente inicializado antes de que el SDK procese el callback de OAuth, lo que evita condiciones de carrera.
    </Info>

    <Warning>
      Para mantener la autenticación después de cerrar y volver a abrir la aplicación, quizá quieras establecer `cacheLocation` en `localstorage`, pero ten en cuenta [los riesgos de almacenar tokens en localstorage](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options). Además, `localstorage` debe tratarse como **transitorio** en las aplicaciones de Capacitor, ya que los datos podrían recuperarse inesperadamente. Lee la [guía sobre almacenamiento en la documentación de Capacitor](https://capacitorjs.com/docs/guides/storage#why-cant-i-just-use-localstorage-or-indexeddb).
    </Warning>
  </Step>

  <Step title="Crear componentes de autenticación" stepNumber={5}>
    Crear archivos de componentes

    <CodeGroup>
      ```shellscript Mac/Linux theme={null}
      mkdir -p src/components && touch src/components/LoginButton.vue && touch src/components/LogoutButton.vue && touch src/components/UserProfile.vue
      ```

      ```powershell Windows theme={null}
      New-Item -ItemType Directory -Force -Path src/components
      New-Item -ItemType File -Path src/components/LoginButton.vue
      New-Item -ItemType File -Path src/components/LogoutButton.vue
      New-Item -ItemType File -Path src/components/UserProfile.vue
      ```
    </CodeGroup>

    Agrega el siguiente código a los nuevos componentes y actualiza los archivos `App.vue` y `HomePage.vue` existentes

    <AuthCodeGroup>
      ```vue src/components/LoginButton.vue lines theme={null}
      <template>
        <ion-button @click="login" expand="block">Log in</ion-button>
      </template>

      <script setup lang="ts">
      import { useAuth0 } from '@auth0/auth0-vue'
      import { Browser } from '@capacitor/browser'
      import { IonButton } from '@ionic/vue'

      const { loginWithRedirect } = useAuth0()

      const login = async () => {
        await loginWithRedirect({
          openUrl: (url: string) =>
            Browser.open({ url, windowName: '_self' }),
        })
      }
      </script>
      ```

      ```vue src/components/LogoutButton.vue lines theme={null}
      <template>
        <ion-button @click="onLogout" expand="block" color="danger">
          Log out
        </ion-button>
      </template>

      <script setup lang="ts">
      import { useAuth0 } from '@auth0/auth0-vue'
      import { Browser } from '@capacitor/browser'
      import { IonButton } from '@ionic/vue'
      import config from '../../capacitor.config'

      const returnTo = `${config.appId}://{yourDomain}/capacitor/${config.appId}/callback`

      const { logout } = useAuth0()

      const onLogout = async () => {
        await logout({
          logoutParams: { returnTo },
          openUrl: (url: string) =>
            Browser.open({ url, windowName: '_self' }),
        })
      }
      </script>
      ```

      ```vue src/components/UserProfile.vue expandable lines theme={null}
      <template>
        <div v-if="isLoading" class="ion-text-center">
          <p>Loading profile...</p>
        </div>
        <div v-else-if="isAuthenticated && user" class="ion-text-center">
          <ion-avatar style="margin: 0 auto; width: 80px; height: 80px;">
            <img :src="user.picture" :alt="user.name" />
          </ion-avatar>
          <h2>{{ user.name }}</h2>
          <p>{{ user.email }}</p>
        </div>
      </template>

      <script setup lang="ts">
      import { useAuth0 } from '@auth0/auth0-vue'
      import { IonAvatar } from '@ionic/vue'

      const { user, isAuthenticated, isLoading } = useAuth0()
      </script>
      ```

      ```vue src/views/HomePage.vue expandable lines theme={null}
      <template>
        <ion-page>
          <ion-header>
            <ion-toolbar>
              <ion-title>Auth0 + Ionic Vue</ion-title>
            </ion-toolbar>
          </ion-header>

          <ion-content class="ion-padding ion-text-center">
            <div v-if="isLoading">
              <ion-spinner />
              <p>Loading...</p>
            </div>

            <div v-else-if="error">
              <h2>Oops!</h2>
              <p>{{ error.message }}</p>
            </div>

            <div v-else-if="isAuthenticated">
              <div style="margin-bottom: 1rem;">
                <UserProfile />
              </div>
              <LogoutButton />
            </div>

            <div v-else>
              <h2>Welcome</h2>
              <p>Get started by signing in to your account</p>
              <LoginButton />
            </div>
          </ion-content>
        </ion-page>
      </template>

      <script setup lang="ts">
      import {
        IonPage,
        IonHeader,
        IonToolbar,
        IonTitle,
        IonContent,
        IonSpinner,
      } from '@ionic/vue'
      import { useAuth0 } from '@auth0/auth0-vue'
      import LoginButton from '../components/LoginButton.vue'
      import LogoutButton from '../components/LogoutButton.vue'
      import UserProfile from '../components/UserProfile.vue'

      const { isAuthenticated, isLoading, error } = useAuth0()
      </script>
      ```

      ```vue src/App.vue expandable lines theme={null}
      <template>
        <ion-app>
          <ion-router-outlet />
        </ion-app>
      </template>

      <script setup lang="ts">
      import { IonApp, IonRouterOutlet } from '@ionic/vue'
      import { useAuth0 } from '@auth0/auth0-vue'
      import { App as CapApp } from '@capacitor/app'
      import { Browser } from '@capacitor/browser'

      const { handleRedirectCallback } = useAuth0()

      CapApp.addListener('appUrlOpen', async ({ url }) => {
        if (url.includes('state') && (url.includes('code') || url.includes('error'))) {
          await handleRedirectCallback(url)
        }
        await Browser.close()
      })
      </script>
      ```
    </AuthCodeGroup>
  </Step>

  <Step title="Ejecute la aplicación" stepNumber={6}>
    Primero, haga la prueba en el navegador:

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

    <Warning>
      Cuando se ejecuta en el navegador con `ionic serve`, la redirección mediante un esquema de URL personalizado no funcionará, porque los navegadores no admiten esquemas de URL personalizados. Para hacer pruebas en el navegador, cambia temporalmente `redirect_uri` a `http://localhost:8100` en `src/main.ts` y agrega `http://localhost:8100` a **Allowed Callback URLs** y **Allowed Logout URLs** de tu aplicación de Auth0 en el Dashboard. Recuerda revertir este cambio antes de compilar para nativo.
    </Warning>

    Para ejecutarlo en un dispositivo o simulador, primero agrega las plataformas nativas:

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

    Luego, compila, sincroniza y ejecuta:

    <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>
      Debes agregar las plataformas nativas con `npx cap add` antes de poder ejecutarlas. Solo es necesario hacerlo una vez por plataforma. Asegúrate primero de haber registrado el [esquema de URL personalizado](#custom-url-scheme-setup) para tu plataforma.
    </Info>
  </Step>
</Steps>

<Check>
  **Punto de control**

  Ahora debería tener una experiencia de Login de Auth0 totalmente funcional en su aplicación Ionic Vue, con Login, cierre de sesión e información del perfil de usuario.
</Check>

***

<div id="advanced-usage">
  ## Uso avanzado
</div>

<Accordion title="Configuración de esquemas de URL personalizados">
  Registre el esquema de URL personalizado de su aplicación para que el sistema operativo pueda redirigir el callback de OAuth de vuelta a su aplicación tras la autenticación.

  ### iOS

  Registre el esquema de URL personalizado en `ios/App/App/Info.plist`:

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

  Sustituya `YOUR_PACKAGE_ID` por el `appId` de `capacitor.config.ts`. Para obtener más información, consulte [Defining a Custom URL Scheme](https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app).

  ### Android

  Agregue un filtro de intents a `android/app/src/main/AndroidManifest.xml`, dentro de la etiqueta `<activity>` principal:

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

  Para obtener más información, consulte [Create Deep Links to App Content](https://developer.android.com/training/app-links/deep-linking).

  <Tip>
    Después de modificar archivos del proyecto nativo, ejecute `npx cap sync` para asegurarse de que los cambios se apliquen.
  </Tip>
</Accordion>

<Accordion title="Protección de rutas con Vue Router">
  Use el `authGuard` integrado del SDK de Auth0 para Vue para proteger las rutas que requieren autenticación:

  ```typescript src/router/index.ts theme={null}
  import { createRouter, createWebHistory } from '@ionic/vue-router'
  import { authGuard } from '@auth0/auth0-vue'
  import HomePage from '../views/HomePage.vue'
  import ProfilePage from '../views/ProfilePage.vue'

  const routes = [
    {
      path: '/',
      name: 'Home',
      component: HomePage,
    },
    {
      path: '/profile',
      name: 'Profile',
      component: ProfilePage,
      beforeEnter: authGuard,
    },
  ]

  const router = createRouter({
    history: createWebHistory(import.meta.env.BASE_URL),
    routes,
  })

  export default router
  ```

  `authGuard` redirige automáticamente a los usuarios no autenticados a la página de Universal Login de Auth0. Después de iniciar sesión, vuelven a la ruta solicitada originalmente.
</Accordion>

<Accordion title="Llamada a API protegidas">
  Configure el parámetro `audience` en la configuración de `createAuth0` para solicitar tokens de acceso para su API:

  ```typescript src/main.ts theme={null}
  app.use(
    createAuth0({
      domain: '{yourDomain}',
      clientId: '{yourClientId}',
      useRefreshTokens: true,
      useRefreshTokensFallback: false,
      authorizationParams: {
        redirect_uri,
        audience: 'YOUR_API_IDENTIFIER',
      },
    })
  )
  ```

  Luego, use `getAccessTokenSilently` en sus componentes para recuperar tokens y realizar llamadas autenticadas a la API:

  ```vue src/components/ApiCall.vue theme={null}
  <template>
    <ion-button @click="callApi" :disabled="loading">
      {{ loading ? 'Calling...' : 'Call Protected API' }}
    </ion-button>
    <pre v-if="response">{{ JSON.stringify(response, null, 2) }}</pre>
  </template>

  <script setup lang="ts">
  import { ref } from 'vue'
  import { useAuth0 } from '@auth0/auth0-vue'
  import { IonButton } from '@ionic/vue'

  const { getAccessTokenSilently } = useAuth0()
  const response = ref(null)
  const loading = ref(false)

  const callApi = async () => {
    try {
      loading.value = true
      const token = await getAccessTokenSilently()

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

      response.value = await res.json()
    } catch (error) {
      console.error('API call failed:', error)
    } finally {
      loading.value = false
    }
  }
  </script>
  ```

  <Tip>
    El método `getAccessTokenSilently` recupera el token de la caché o lo renueva automáticamente mediante el token de actualización cuando sea necesario.
  </Tip>
</Accordion>

<Accordion title="Uso del patrón defineComponent">
  Si prefieres el patrón explícito `defineComponent` en lugar de `<script setup>`, así es como se ve el componente LoginButton con este enfoque:

  ```vue src/components/LoginButton.vue theme={null}
  <template>
    <ion-button @click="login" expand="block">Log in</ion-button>
  </template>

  <script lang="ts">
  import { defineComponent } from 'vue'
  import { useAuth0 } from '@auth0/auth0-vue'
  import { Browser } from '@capacitor/browser'
  import { IonButton } from '@ionic/vue'

  export default defineComponent({
    components: { IonButton },
    setup() {
      const { loginWithRedirect } = useAuth0()

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

      return { login }
    },
  })
  </script>
  ```

  El patrón `defineComponent` requiere registrar explícitamente los componentes hijo y devolver los valores desde la función `setup()`. Ambos patrones son totalmente compatibles con el SDK de Auth0 para Vue.
</Accordion>

<Accordion title="Problemas comunes y soluciones">
  ### Error de URL de callback no coincidente

  **Solución:** Verifica que la URL de callback en tu Auth0 Dashboard coincida exactamente con la URL construida en tu aplicación. Asegúrate de que `YOUR_PACKAGE_ID` coincida con el campo `appId` en tu `capacitor.config.ts`.

  ### Error "PKCE not allowed"

  **Solución:**

  1. Ve a Auth0 Dashboard > Applications > Your Application
  2. Cambia **Application Type** a **Native**
  3. Establece **Token Endpoint Authentication Method** en `None`
  4. Guarda los cambios y vuelve a intentarlo

  ### SSO no funciona en iOS

  El plugin Browser de Capacitor usa `SFSafariViewController`, que no comparte cookies con Safari en iOS 11+. Si necesitas SSO, usa un plugin compatible que utilice [ASWebAuthenticationSession](https://developer.apple.com/documentation/authenticationservices/aswebauthenticationsession).

  ### Login funciona, pero el usuario sigue sin autenticarse después de reiniciar la aplicación

  Habilita `cacheLocation: 'localstorage'` en la configuración de `createAuth0` para conservar los tokens entre reinicios de la aplicación. Ten en cuenta las [implicaciones de seguridad](https://auth0.com/docs/libraries/auth0-single-page-app-sdk#change-storage-options). El SDK también admite [implementaciones de caché personalizadas](https://github.com/auth0/auth0-spa-js/blob/master/EXAMPLES.md#creating-a-custom-cache) para un almacenamiento más seguro.

  ### El navegador no se cierra después del login

  Asegúrate de llamar a `Browser.close()` dentro del listener del evento `appUrlOpen` en tu componente `App.vue`. En Android, `Browser.close()` no realiza ninguna acción, por lo que el navegador se cierra automáticamente.

  ### La página de login se abre en la aplicación de navegador predeterminada del dispositivo

  Si la página de login se abre en Safari o Chrome en lugar de un navegador integrado en la aplicación, asegúrate de pasar el callback `openUrl` a `loginWithRedirect` y `logout`. Sin él, el SDK usa `window.location.href` de forma predeterminada, lo que redirige toda la app fuera de la aplicación.
</Accordion>
