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

> Transiciona sin problemas a los usuarios desde tu aplicación para iOS o Android a un flujo de suscripción seguro y autenticado en tu aplicación web mediante SSO de aplicaciones nativas a web y tokens de transferencia de sesión.

# Caso de uso: Configurar flujos de pago de móvil a web con SSO de aplicaciones nativas a web

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>;
};

<Card title="Antes de comenzar">
  1. Cree un inquilino de Auth0 para registrar y configurar sus aplicaciones nativas y web.

  2. Instale y configure [Auth0 CLI](https://github.com/auth0/auth0-cli) para su inquilino de Auth0.

  3. Agregue la autenticación de Auth0 a su aplicación nativa mediante las guías de inicio rápido correspondientes para su plataforma:

  * [Guía de inicio rápido de iOS Swift](/es/docs/quickstart/native/ios-swift/interactive)
  * [Guía de inicio rápido de Android](/es/docs/quickstart/native/android/interactive)

  4. Agregue compatibilidad con [refresh\_token](/es/docs/secure/tokens/refresh-tokens/get-refresh-tokens) a su aplicación nativa.

  5. Agregue la autenticación de Auth0 a su aplicación web mediante la [guía de inicio rápido para aplicaciones de una sola página con React](/es/docs/quickstart/spa/react/interactive).
</Card>

[Inicio de sesión único (SSO) de aplicaciones nativas a web](/es/docs/authenticate/single-sign-on/native-to-web) le permite crear una experiencia de usuario fluida y segura entre su aplicación nativa y un flujo web de suscripción de pago. El <Tooltip tip="Inicio de sesión único (SSO): servicio que, después de que un usuario inicia sesión en una aplicación, inicia automáticamente la sesión de ese usuario en otras aplicaciones." cta="Ver glosario" href="/es/docs/glossary?term=SSO">SSO</Tooltip> de aplicaciones nativas a web permite que la aplicación nativa envíe el contexto de autenticación del usuario a la aplicación web mediante un `session_transfer_token` seguro y de corta duración.

Las secciones siguientes describen cómo agregar:

* A su aplicación nativa, un botón Suscribirse ahora que permite a los usuarios autenticados contratar un plan de suscripción de pago mediante un proceso de compra web seguro.
* A su aplicación web, una página de suscripción que permite a los usuarios seleccionar suscripciones de membresía sin tener que volver a iniciar sesión.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Este caso de uso se centra en aplicaciones web basadas en React que usan el SDK de React de Auth0.

  Si usa un framework diferente, como Node o Express, la lógica para administrar `session_transfer_token`, ya sea mediante un parámetro de URL o una cookie, puede adaptarse según corresponda.
</Callout>

<div id="configure-auth0-cli">
  ## Configura la Auth0 CLI
</div>

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Usa la [Auth0 CLI](https://github.com/auth0/auth0-cli) para configurar tu inquilino de Auth0. También puedes usar la [Auth0 Management API](https://auth0.com/docs/api/management/v2); para obtener más información, consulta [Configurar SSO de aplicaciones nativas a web](/es/docs/authenticate/single-sign-on/native-to-web/configure-implement-native-to-web#configure-native-applications).
</Callout>

Sigue estos pasos para autenticarte en tu inquilino de Auth0 con la [Auth0 CLI](https://github.com/auth0/auth0-cli):

1. Inicializa la Auth0 CLI

```bash lines theme={null}
auth0 login
```

2. Seleccione **Como usuario** y siga el flujo de inicio de sesión.

```bash lines theme={null}
How would you like to authenticate?
> As a user
  As a machine
```

3. Selecciona el inquilino de Auth0 en el que quieras habilitar el SSO de aplicaciones nativas a web.

<div id="configure-auth0">
  ## Configura Auth0
</div>

<div id="enable-native-to-web-sso-in-your-native-application">
  ### Habilite el SSO de aplicaciones nativas a web en su aplicación nativa
</div>

El SSO de aplicaciones nativas a web utiliza un `session_transfer_token` para establecer el SSO desde una aplicación nativa a una aplicación web. El `session_transfer_token` permite a Auth0 identificar de forma segura al usuario, la aplicación nativa de origen y contexto adicional. Para obtener más información, consulte [SSO de aplicaciones nativas a web](/es/docs/authenticate/single-sign-on/native-to-web/configure-implement-native-to-web).

Habilite el SSO de aplicaciones nativas a web con Auth0 CLI:

export const codeExample1 = `auth0 apps session-transfer update {yourClientId} --can-create-token=true --enforce-device-binding=asn`;

<AuthCodeBlock children={codeExample1} language="bash" />

<div id="enable-native-to-web-sso-in-your-web-application">
  ### Habilita el SSO de aplicaciones nativas a web en tu aplicación web
</div>

Configura la aplicación web para que acepte el `session_transfer_token` para la autenticación mediante una cookie o un parámetro de URL con Auth0 CLI:

export const codeExample2 = `auth0 apps session-transfer update {yourClientId}  --allowed-auth-methods=cookie,query`;

<AuthCodeBlock children={codeExample2} language="bash" />

Si el `session_transfer_token` se inyecta en el navegador mediante una cookie, no se requieren cambios adicionales en su aplicación web. El único requisito es que el navegador vaya al [URI de inicio de sesión de su aplicación](https://sus.auth0.com/docs/get-started/applications/application-settings#application-uris) para procesar la redirección del usuario al endpoint `/authorize` de su inquilino de Auth0.

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Puede configurar el URI de inicio de sesión de la aplicación en la configuración de su aplicación en Auth0 Dashboard. Esta es la ruta a la que Auth0 redirigirá a los usuarios cuando el inicio de sesión se active desde fuentes externas.
</Callout>

<div id="create-a-subscription-page-in-the-web-application">
  ## Crear una página de suscripción en la aplicación web
</div>

Agrega un nuevo archivo en `/src/views/` para crear la página de suscripción:

<div id="step-1-add-a-new-view-file">
  ### Paso 1: Agrega un nuevo archivo de vista
</div>

Crea un archivo en `src/views/JoinMembership.js`. Este archivo solicitará a los usuarios que completen una suscripción de pago.

```js lines expandable theme={null}
import React, { useEffect } from "react";
import { useAuth0 } from "@auth0/auth0-react";
import { useLocation } from "react-router-dom";
import { Container, Button } from "reactstrap";
import Loading from "../components/Loading";

const JoinMembership = () => {
  const { isAuthenticated, isLoading, loginWithRedirect } = useAuth0();
  const location = useLocation();

  useEffect(() => {
    if (isLoading || isAuthenticated) return;

    const params = new URLSearchParams(location.search);
    const token = params.get("session_transfer_token");

    const redirectOptions = {
      appState: { returnTo: "/join-membership" },
      authorizationParams: {},
    };

    if (token) {
      redirectOptions.authorizationParams.session_transfer_token = token;
    }

    loginWithRedirect(redirectOptions);
  }, [isAuthenticated, isLoading, loginWithRedirect, location.search]);

  if (isLoading) {
    return <Loading />;
  }

  if (!isAuthenticated) {
    return <p>Redirecting to login...</p>;
  }

  return (
    <Container className="mt-5">
      <h1>Choose a Subscription Plan</h1>
      <Button color="primary" className="mb-3" onClick={() => alert("Subscribed to Basic!")}>
        Basic – $5/month
      </Button>
      <Button color="secondary" className="mb-3" onClick={() => alert("Subscribed to Pro!")}>
        Pro – $10/month
      </Button>
      <Button color="success" className="mb-3" onClick={() => alert("Subscribed to Premium!")}>
        Premium – $20/month
      </Button>
    </Container>
  );
};

export default JoinMembership;
```

<div id="step-2-add-a-new-route">
  ### Paso 2: Añada una nueva ruta
</div>

Edite el archivo `src/App.js` y añada una ruta `/join-membership` a la nueva página de suscripción:

```js lines theme={null}
import JoinMembership from "./views/JoinMembership";

 {/* Redirigir a la página de unirse a la membresía */}
<Route path="/join-membership" component={JoinMembership} />
```

La nueva ruta `/join-membership`:

* Determina si el usuario está autenticado. Si no lo está, redirige al usuario a la página de <Tooltip tip="Universal Login: Su aplicación redirige a Universal Login, alojado en el Servidor de autorización de Auth0, para verificar la identidad del usuario." cta="Ver glosario" href="/es/docs/glossary?term=Universal+Login">Universal Login</Tooltip>.
* Si se agrega un `session_transfer_token` como parámetro de URL, el token se pasa en la solicitud de autenticación.
* Una vez autenticado, al usuario se le mostrarán botones para suscribirse a distintos planes de membresía.

<Warning>
  Ejecute su aplicación React y vaya a `http://localhost:3000/join-membership`

  * Si el usuario está autenticado, verá las opciones de suscripción.
  * Si el usuario no está autenticado, se le redirige automáticamente a la página de Universal Login de Auth0.

    * Si la URL incluye un `session_transfer_token`, se incluirá en la solicitud de inicio de sesión a Auth0.
    * Si no, el inicio de sesión continuará con la autenticación web estándar.

  Cuando el usuario inicie sesión, volverá a la página `/join-membership` para seleccionar las opciones de suscripción.
</Warning>

<div id="configure-the-native-application">
  ## Configura la aplicación nativa
</div>

Tu aplicación nativa debe intercambiar el `refresh_token` por un `session_transfer_token` justo antes de iniciar la aplicación web. Para ello, agrega el intercambio de transferencia de sesión y la lógica de inicio de la aplicación web dentro del mismo controlador de eventos; por ejemplo, el método `onClick` del botón.

<div id="ios">
  ### iOS
</div>

Los siguientes pasos describen cómo agregar el pago de móvil a web en aplicaciones nativas de iOS:

<div id="step-1-add-a-subscribe-to-membership-button">
  #### Paso 1: Agrega un botón `Subscribe to Membership`
</div>

Para iniciar el flujo de suscripción basado en la web desde tu aplicación nativa de iOS, agrega un botón `Subscribe to Membership` al archivo `ProfileView.swift`.

Edita el cuerpo del archivo `ProfileView.swift` para incluir un botón debajo de la información del usuario:

```swift lines theme={null}
import SwiftUI

struct ProfileView: View {
    let user: User
    var onSubscribe: () -> Void = {}

    var body: some View {
        List {
            Section(header: ProfileHeader(picture: user.picture)) {
                ProfileCell(key: "ID", value: user.id)
                ProfileCell(key: "Name", value: user.name)
                ProfileCell(key: "Email", value: user.email)
                ProfileCell(key: "Email verified?", value: user.emailVerified)
                ProfileCell(key: "Updated at", value: user.updatedAt)
            }

            Section {
                Button("Subscribe to Membership", action: onSubscribe)
            }
        }
    }
}
```

El archivo `ProfileView.swift` agrega un botón `Subscribe to Membership` y usa una clausura `onSubscribe` para definir el comportamiento al seleccionarlo.

<div id="step-2-implement-the-subscription-flow-using-native-to-web-sso">
  #### Paso 2: Implementa el flujo de suscripción con SSO de aplicaciones nativas a web
</div>

Edita el archivo `MainView.swift` para definir el comportamiento del botón `Subscribe to Membership`:

export const codeExample3 = `import SwiftUI
import Auth0
import WebKit

struct MainView: View {
    @State var user: User?

    var body: some View {
        if let user = self.user {
            VStack {
                ProfileView(user: user, onSubscribe: launchSubscription)
                Button("Cerrar sesión", action: self.logout)
            }
        } else {
            VStack {
                HeroView()
                Button("Iniciar sesión", action: self.login)
            }
        }
    }

    func login() {
            Auth0
                .webAuth()
                .audience("https://sample.api.com")
                .scope("profile email offline_access openid")
                //.useHTTPS() // Usa una URL de callback de Universal Link en iOS 17.4+ / macOS 14.4+
                .start { result in
                    switch result {
                    case .success(let credentials):
                        self.user = User(from: credentials.idToken)
                        let manager = CredentialsManager(authentication: Auth0.authentication())
                        let success = manager.store(credentials: credentials)
                        print("¿Se almacenaron las credenciales? \(credentials.refreshToken)")
                    case .failure(let error):
                        print("Error: \(error)")
                    }
                }
        }

    func logout() {
        Auth0
            .webAuth()
            .useHTTPS()
            .clearSession { result in
                switch result {
                case .success:
                    self.user = nil
                case .failure(let error):
                    print("Error: \(error)")
                }
            }
    }

    func launchSubscription() {
        let credentialsManager = CredentialsManager(authentication: Auth0.authentication())

        credentialsManager.credentials { result in
            switch result {
            case .success(let credentials):
                let refreshToken = credentials.refreshToken ?? ""

                Auth0
                    .authentication()
                    .ssoExchange(withRefreshToken: refreshToken)
                    .start { result in
                        switch result {
                        case .success(let ssoCredentials):
                            DispatchQueue.main.async {
                                let cookie = HTTPCookie(properties: [
                                    .domain: "{yourDomain}", // Reemplázalo por el dominio real de tu inquilino de Auth0
                                    .path: "/",
                                    .name: "auth0_session_transfer_token",
                                    .value: ssoCredentials.sessionTransferToken,
                                    .expires: ssoCredentials.expiresIn,
                                    .secure: true
                                ])!

                                let webView = WKWebView()
                                let store = webView.configuration.websiteDataStore.httpCookieStore
                                store.setCookie(cookie) {
                                    let url = URL(string: "http://localhost:3000/join-membership")!
                                    let request = URLRequest(url: url)
                                    webView.load(request)

                                    let vc = UIViewController()
                                    vc.view = webView
                                    UIApplication.shared.windows.first?.rootViewController?.present(vc, animated: true)
                                }
                            }

                        case .failure(let error):
                            print("No se pudo obtener el token de SSO: \(error)")
                        }
                    }

            case .failure(let error):
                print("Error al cargar las credenciales: \(error)")
            }
        }
    }
}`;

<AuthCodeBlock children={codeExample3} language="swift" />

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Este ejemplo usa la audiencia `https://sample.api.com` con fines de demostración. Puede crear una API con este identificador en su inquilino de Auth0 o reemplazarlo por el identificador de su propia API.

  Para obtener más información, consulte [Configurar API](/es/docs/get-started/auth0-overview/set-up-apis).
</Callout>

Esto permite que el usuario seleccione `Subscribe to Membership` en la aplicación nativa y comience de inmediato el proceso de suscripción en la aplicación web sin volver a iniciar sesión.

<div id="android">
  ### Android
</div>

Los siguientes pasos explican cómo añadir pagos desde móviles a la web en aplicaciones nativas de Android:

<div id="step-1-add-a-subscribe-button-to-the-main-page">
  #### Paso 1: Agrega un botón de suscripción a la página principal
</div>

Para iniciar el flujo de suscripción basado en web desde tu aplicación nativa de Android, agrega a la interfaz de usuario un botón `Subscribe to Membership`.

Edita el archivo `MainActivity.kt` y agrega el siguiente código al método `onCreate()`:

```kotlin wrap lines theme={null}
binding.buttonSubscribe.setOnClickListener { launchSubscriptionFlow() }
```

Edite el archivo `activity_main.xml` para incluir el código que aparece a continuación después del botón `@+id/button_patch_metadata`:

```xml lines theme={null}
<Button
    android:id="@+id/buttonSubscribe"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Subscribe to Membership" />
```

<div id="step-2-implement-subscription-flow-using-native-to-web-sso">
  #### Paso 2: Implemente el flujo de suscripción mediante SSO de aplicaciones nativas a web
</div>

Edite el archivo `MainActivity.kt` para definir el comportamiento del botón `Subscribe to Membership`:

1. Amplíe el flujo de inicio de sesión y gestione la acción de suscripción:

```kotlin lines theme={null}
// Importaciones necesarias
import com.auth0.android.authentication.storage.SecureCredentialsManager
import com.auth0.android.authentication.storage.SharedPreferencesStorage
import com.auth0.android.result.SSOCredentials
```

2. Actualiza el método `onCreate()` para incluir `credentialsManager:`

```kotlin lines theme={null}
override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Configurar el objeto de cuenta con los detalles de la aplicación Auth0
        account =  Auth0.getInstance(
            getString(R.string.com_auth0_client_id),
            getString(R.string.com_auth0_domain)
        )

        // Asociar el clic del botón con la acción de inicio de sesión
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.buttonLogin.setOnClickListener { loginWithBrowser() }
        binding.buttonLogout.setOnClickListener { logout() }
        binding.buttonGetMetadata.setOnClickListener { getUserMetadata() }
        binding.buttonPatchMetadata.setOnClickListener { patchUserMetadata() }
        binding.buttonSubscribe.setOnClickListener { launchSubscriptionFlow() }

        secureCredentialsManager = SecureCredentialsManager(
            this,
            AuthenticationAPIClient(account),
            SharedPreferencesStorage(this)
        )

    }
```

3. Actualiza el método `loginwithBrowser()` para almacenar las credenciales mediante `credentialsManager:`

```kotlin lines theme={null}
private fun loginWithBrowser() {
    WebAuthProvider.login(account)
        .withScheme(getString(R.string.com_auth0_scheme))
        .withScope("openid profile email offline_access")
        .withAudience("https://example.api.com")
        .start(this, object : Callback<Credentials, AuthenticationException> {
            override fun onSuccess(credentials: Credentials) {
                secureCredentialsManager.saveCredentials(credentials)
                cachedCredentials = credentials
                showSnackBar("Success: ${credentials.accessToken}")
                updateUI()
                showUserProfile()
            }

            override fun onFailure(exception: AuthenticationException) {
                showSnackBar("Failure: ${exception.getCode()}")
            }
        })
}
```

<Callout icon="file-lines" color="#0EA5E9" iconType="regular">
  Este ejemplo usa la audiencia `https://sample.api.com` únicamente con fines de demostración. Puede crear una API con este identificador en su inquilino de Auth0 o sustituirlo por el identificador de su propia API.

  Para obtener más información, lea [Configurar APIs](/es/docs/get-started/auth0-overview/set-up-apis).
</Callout>

4. Agregue el método `launchSubscriptionFlow()` para abrir la aplicación web:

```kotlin lines expandable theme={null}
private fun launchSubscriptionFlow() {
    secureCredentialsManager.getSsoCredentials(
        mapOf(),  // parámetros opcionales
        object : Callback<SSOCredentials, CredentialsManagerException> {
            override fun onSuccess(result: SSOCredentials) {
                val sessionToken = result.sessionTransferToken

                val cookieValue =
                    "auth0_session_transfer_token=$sessionToken; Path=/; Secure; HttpOnly; SameSite=None"
                val cookieManager = android.webkit.CookieManager.getInstance()
                cookieManager.setAcceptCookie(true)
                cookieManager.setCookie("https://${getString(R.string.com_auth0_domain)}", cookieValue)

                val webView = android.webkit.WebView(this@MainActivity)
                webView.settings.javaScriptEnabled = true
                webView.webViewClient = object : android.webkit.WebViewClient() {
                    override fun shouldOverrideUrlLoading(view: android.webkit.WebView?, url: String?) = false
                }

                webView.loadUrl("http://localhost:3000/join-membership")
                setContentView(webView)
            }

            override fun onFailure(error: CredentialsManagerException) {
                showSnackBar("Failed to get session transfer token: ${error.message}")
            }
        }
    )
}
```

Esto permite que el usuario seleccione `Subscribe to Membership` en la aplicación nativa y comience de inmediato el proceso de suscripción en la aplicación web sin tener que volver a iniciar sesión.

<div id="test-your-native-to-web-sso-implementation">
  ## Pruebe su implementación de SSO de aplicaciones nativas a web
</div>

Una vez que todo esté configurado, ejecute su aplicación nativa de iOS o Android para iniciar sesión, vaya al perfil o a la pantalla principal y seleccione el botón **Subscribe to Membership**.

Sucede lo siguiente:

* El `refresh_token` almacenado se utiliza para solicitar un `session_transfer_token` seguro
* El `session_transfer_token` se inserta en una cookie para su dominio de Auth0
* Se utiliza un `WKWebView` para cargar la ruta `/join-membership` de su aplicación web
* La aplicación web recibe el `session_transfer_token` y completa el inicio de sesión mediante SSO de aplicaciones nativas a web
* El usuario ve inmediatamente las opciones de suscripción en la aplicación web

Ha creado una experiencia fluida en la que el usuario de una aplicación móvil nativa puede iniciar un flujo seguro y autenticado en una aplicación web sin tener que volver a iniciar sesión.

<div id="next-steps">
  ## Próximos pasos
</div>

* Explora más opciones de configuración para el SSO de aplicaciones nativas a web:Profundiza en el tiempo de vida de la sesión, la rotación de <Tooltip tip="Token de actualización: token que se usa para obtener un nuevo Token de acceso sin obligar a los usuarios a volver a iniciar sesión." cta="Ver glosario" href="/es/docs/glossary?term=refresh+token">token de actualización</Tooltip>, la vinculación de dispositivos y la revocación en cascada en la [documentación de SSO de aplicaciones nativas a web](/es/docs/authenticate/single-sign-on/native-to-web).
* Personaliza la experiencia posterior al inicio de sesión con el perfilado progresivo:Usa el [formulario de perfilado progresivo](/es/docs/customize/forms/configure-progressive-profile-form) de Auth0 para recopilar datos de usuario adicionales después del inicio de sesión —como preferencias del plan, dirección o intención de pago— antes de mostrar las opciones de suscripción.
