Saltar al contenido principal

Cómo iniciar sesión con Auth0 usando Capacitor

Añade login de Auth0 a una app de Capacitor 8 con OIDC y PKCE: configuración del dashboard de Auth0, URLs de callback, audiencia de API, tokens de refresco, logout y solución de problemas.

Auth0 Universal Login abierto desde una app de Capacitor a través del navegador del sistema

Para iniciar sesión con Auth0 en una app de Capacitor, crea una Nativo aplicación en Auth0, registra una URL de callback con esquema personalizado como com.example.app://oauth/auth0, y ejecuta el flujo de autorización OpenID Connect code con PKCE a través de un navegador del sistema. Con @capgo/capacitor-social-login eso es una sola initialize llamada con tus endpoints de Auth0 y una SocialLogin.login({ provider: 'oauth2', options: { providerId: 'auth0' } }).

Esta guía cubre la configuración del dashboard de Auth0, el cliente code para iOS, Android y web, tokens de acceso API, tokens de refresco, cierre de sesión y los errores con los que te encontrarás. Está escrita para Capacitor 8 a octubre de 2026.

Cómo funciona el flujo de Auth0 en Capacitor

Auth0 aloja la página de inicio de sesión (Universal Login). Tu app nunca ve la contraseña. El flujo es:

  1. La app genera un verificador y un desafío PKCE, y luego abre https://YOUR_TENANT/authorize en un navegador seguro.
  2. El usuario inicia sesión (contraseña, social, passkey, MFA, lo que hayas configurado en Auth0).
  3. Auth0 redirige a tu URL de callback con un code.
  4. La app intercambia el code y el verificador PKCE en /oauth/token por un token de ID, un token de acceso y, opcionalmente, un token de refresco.

El navegador utilizado depende de la plataforma:

Plataforma Navegador Manejo de callbacks
iOS ASWebAuthenticationSession Manejado por el sistema, sin Info.plist cambiar
Android WebView integrada por defecto, o Chrome Custom Tabs con androidUseCustomTabs: true Custom Tabs requieren un intent filter
Web Popup (por defecto) o redirección a página completa handleRedirectCallback() en la página de retorno

En Android, usa Custom Tabs. Comparten cookies con Chrome, soportan passkeys y gestores de contraseñas, y siguen el estándar RFC 8252 (OAuth para apps nativas), que es lo que espera Auth0.

Paso 1: Configura la aplicación de Auth0

  1. En el Dashboard de Auth0, ve a Aplicaciones > Aplicaciones > Crear aplicación.
  2. Elige Nativo and create it.
  3. En el Configuración pestaña, toma nota de la Dominio (por ejemplo example.eu.auth0.com) y la ID de cliente.
  4. En Credenciales, comprueba que el método de autenticación es Ninguno. Esa es la configuración de cliente público utilizada con PKCE.

URLs de callback y logout

Completa estos campos Configuración > URIs de la aplicación:

Campo Valor para móvil Valor para web
URLs de callback permitidas com.example.app://oauth/auth0 https://app.example.com/auth/callback
URLs de logout permitidas com.example.app://oauth/logout https://app.example.com/
Orígenes web permitidos No es necesario https://app.example.com

Separa varios valores con comas. Usa tu Capacitor appId como scheme. Un scheme de dominio inverso evita colisiones con otras apps. Si también publicas un build web, muchos equipos crean una Aplicación de página única en Auth0 para ello, de modo que la configuración web y móvil no se mezclen.

Refrescar tokens

Si los usuarios deben permanecer iniciados en la sesión:

  1. En Settings > Refresh Token Rotation, activa la rotación. Cada refresh devuelve un nuevo refresh token e invalida el anterior.
  2. Configura una duración absoluta y de inactividad adecuada a tu producto.
  3. Si llamas a tu propio API, abre Aplicaciones > APIs > tu API > Configuración y habilita Permitir acceso sin conexión.
  4. Solicita el offline_access scope en la app.

audiencia de API

Si tu backend valida los access tokens de Auth0, crea un API en Aplicaciones > APIs con un identificador como https://api.example.com. Pasa ese identificador como audience. Sin él, el access token solo servirá para el /userinfo endpoint.

Paso 2: Instalar y configurar el plugin

bun add @capgo/capacitor-social-login
bunx cap sync

Si Auth0 es tu único proveedor, desactiva los SDKs sociales incluidos para mantener el binario pequeño:

// capacitor.config.ts
plugins: {
  SocialLogin: {
    providers: { google: false, facebook: false, apple: false, twitter: false },
  },
},

El motor OAuth2 genérico no depende de esos SDKs.

Filtro de intent de Android para Custom Tabs

Añade el esquema de callback a MainActivity en android/app/src/main/AndroidManifest.xml:

<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="com.example.app" android:host="oauth" />
</intent-filter>

La plantilla de Capacitor ya configura android:launchMode="singleTask" en MainActivity, que necesita la redirección. Consérvalo.

Paso 3: Inicializa el proveedor de Auth0

import { Capacitor } from '@capacitor/core';
import { SocialLogin } from '@capgo/capacitor-social-login';

const AUTH0_DOMAIN = 'https://example.eu.auth0.com';
const isWeb = Capacitor.getPlatform() === 'web';

export async function initAuth() {
  await SocialLogin.initialize({
    oauth2: {
      auth0: {
        appId: 'YOUR_AUTH0_CLIENT_ID',
        authorizationBaseUrl: `${AUTH0_DOMAIN}/authorize`,
        accessTokenEndpoint: `${AUTH0_DOMAIN}/oauth/token`,
        resourceUrl: `${AUTH0_DOMAIN}/userinfo`,
        redirectUrl: isWeb
          ? 'https://app.example.com/auth/callback'
          : 'com.example.app://oauth/auth0',
        scope: 'openid profile email offline_access',
        pkceEnabled: true,
        additionalParameters: {
          audience: 'https://api.example.com',
        },
        logoutUrl: `${AUTH0_DOMAIN}/oidc/logout`,
        postLogoutRedirectUrl: isWeb
          ? 'https://app.example.com/'
          : 'com.example.app://oauth/logout',
        androidUseCustomTabs: true,
      },
    },
  });
}

Puedes reemplazar los endpoints explícitos con issuerUrl: AUTH0_DOMAIN. El plugin luego lee /.well-known/openid-configuration. Los valores explícitos tienen prioridad sobre los detectados, lo cual ayuda cuando usas un dominio personalizado de Auth0.

Si estás migrando desde Ionic Auth Connect, el plugin también exporta SocialLoginAuthConnect con un auth0 preset que toma domain, clientId, redirectUrl y audience. Consulta la guía de migración de Auth Connect.

Paso 4: Iniciar sesión

import { SocialLogin } from '@capgo/capacitor-social-login';

export async function signInWithAuth0() {
  try {
    const { result } = await SocialLogin.login({
      provider: 'oauth2',
      options: { providerId: 'auth0' },
    });

    return {
      idToken: result.idToken,
      accessToken: result.accessToken?.token,
      expiresAt: result.accessToken?.expires,
      refreshToken: result.refreshToken,
      user: result.resourceData, // JSON from /userinfo
    };
  } catch (error: any) {
    if (error?.code === 'USER_CANCELLED') return null;
    throw error;
  }
}

Opciones de inicio de sesión útiles:

  • prompt: 'login' fuerza la página de inicio de sesión aunque Auth0 aún tenga una cookie de sesión.
  • loginHint: 'user@example.com' precarga el correo electrónico.
  • additionalParameters: { connection: 'google-oauth2' } omite Universal Login y va directamente a una conexión.
  • additionalParameters: { screen_hint: 'signup' } abre la pantalla de registro.

Callback de redirección web

En web, el flujo de popup predeterminado no requiere nada extra. Si usas flow: 'redirect', lee el resultado en la página de callback:

const result = await SocialLogin.handleRedirectCallback();
if (result?.provider === 'oauth2') {
  console.log(result.result.idToken);
}

handleRedirectCallback es solo para web y se rechaza en iOS y Android.

Paso 5: Lee el ID token y llama a tu API

Decodifica el ID token en el cliente solo para mostrarlo:

const { claims } = await SocialLogin.decodeIdToken({ idToken: result.idToken! });
console.log(claims.email, claims.name, claims.sub);

decodeIdToken no verifica la firma. Para cualquier cosa relacionada con la seguridad, envía el access token a tu API y validadlo allí:

import { createRemoteJWKSet, jwtVerify } from 'jose';

const jwks = createRemoteJWKSet(new URL('https://example.eu.auth0.com/.well-known/jwks.json'));

export async function verifyAuth0AccessToken(token: string) {
  const { payload } = await jwtVerify(token, jwks, {
    issuer: 'https://example.eu.auth0.com/', // Auth0 issuers end with a slash
    audience: 'https://api.example.com',
  });
  return payload; // payload.sub is the Auth0 user ID
}

Paso 6: Actualiza el access token

import { SocialLogin } from '@capgo/capacitor-social-login';

export async function getValidAccessToken() {
  const { isLoggedIn } = await SocialLogin.isLoggedIn({ provider: 'oauth2', providerId: 'auth0' });

  if (!isLoggedIn) {
    // access token expired: try the stored refresh token
    try {
      await SocialLogin.refresh({ provider: 'oauth2', options: { providerId: 'auth0' } });
    } catch {
      // refresh token expired, revoked or already rotated: sign in again
      const loginResult = await signInWithAuth0();
      if (!loginResult) throw new Error('Sign-in cancelled');
    }
  }

  const { accessToken } = await SocialLogin.getAuthorizationCode({
    provider: 'oauth2',
    providerId: 'auth0',
  });
  return accessToken;
}

refresh se rechaza cuando el refresh token está caducado o revocado. Con la rotación activada, un refresh token que ya se usó también falla, así que maneja siempre el rechazo enviando al usuario de nuevo a iniciar sesión.

refresh usa el refresh token que el plugin guardó al iniciar sesión. Si guardas el refresh token tú mismo, llama a SocialLogin.refreshToken({ provider: 'oauth2', providerId: 'auth0', refreshToken }), que devuelve la respuesta completa del nuevo token. Con la rotación activada, guarda el nuevo refresh token cada vez.

El plugin guarda su copia del token en almacenamiento privado de la app. Si tu revisión de seguridad exige Keychain o Keystore, guarda el refresh token con NativeBiometric.setData({ key, value }) de los @capgo/capacitor-native-biometric y pásalo a refreshToken tú mismo. Nuestra guía de almacenamiento seguro de tokens compara las opciones.

Paso 7: Cerrar sesión

await SocialLogin.logout({ provider: 'oauth2', providerId: 'auth0' });

El plugin elimina los tokens almacenados y luego abre logoutUrl con id_token_hint y post_logout_redirect_uri para que Auth0 borre su cookie de sesión. El /oidc/logout endpoint entiende esos parámetros, y la URL de redirección debe estar en la lista de URLs de logout permitidas.

En iOS y Android, la página de finalización de sesión se abre en el navegador del sistema, por lo que el usuario sale brevemente de la app. Si solo quieres un cierre de sesión local, omite logoutUrl y pasar prompt: 'login' en el próximo inicio de sesión para que una sesión de Auth0 recordada no vuelva a iniciar al usuario automáticamente. Configuración iosPrefersEphemeralSession: true también evita las cookies compartidas en iOS, a costa de no tener SSO entre apps.

Solución de problemas

Error Causa Solución
Callback URL mismatch URL de redirección no está en las URLs de callback permitidas Copia el valor exacto de code al dashboard, verifica el scheme y el host
Unauthorized o invalid_client en /oauth/token El tipo de app no es Native o el método de autenticación no es None Recrea como Native, configura la autenticación del token endpoint en None
No refreshToken en el resultado offline_access falta o API no permite acceso offline Añade el scope, activa Allow Offline Access, activa la rotación
El access token no puede ser verificado por API No audience enviado Añadir audience en additionalParameters
La app no se reabre tras iniciar sesión en Android El scheme o host del intent filter no coincide redirectUrl Coincidir com.example.app y oauth exactamente
OAuth2 provider "auth0" not configured login se llama antes de initialize o el key no coincide Await initialize al inicio, usa el mismo providerId
La página de logout sigue abierta post_logout_redirect_uri no está en Allowed Logout URLs Añádela o usa solo logout local
Error CORS en el intercambio de token El origen no está en Allowed Web Origins Añade el origen web o usa una aplicación SPA para web

Configurar logsEnabled: true en la configuración del provider para imprimir las URLs generadas y los detalles del intercambio de tokens mientras debugueas.

Lanza correcciones de auth sin pasar por la tienda

Cambiar los scopes, la audiencia o el manejo de errores solo requiere TypeScript. Con actualizaciones Live Update de Capgo puedes lanzar esos fixes a los usuarios el mismo día. Los cambios nativos, como un nuevo intent filter, aún requieren un nuevo binario, que Build de Capgo puedes generar en la nube.

Live updates para apps Capacitor

Cuando un bug de la capa web está en producción, publica el fix a través de Capgo en lugar de esperar días a la aprobación de la app store. Los usuarios reciben la actualización en segundo plano mientras los cambios nativos siguen el flujo de revisión habitual.

Lo último de nuestro blog

Capgo te da la información clave que necesitas para crear una app móvil realmente profesional.