Use Case: Configure mobile-to-web payment flows using Native to Web SSO
Seamlessly transition users from your iOS or Android app into a secure, authenticated subscription flow in your web app using Native to Web Single Sign-On (SSO) and session transfer tokens.
Before you start
Create an Auth0 tenant to register and configure your native and web applications.
Install and configure Auth0 CLI for your Auth0 tenant.
Add Auth0 Authentication to your native application using the appropriate Quickstarts for your platform:
Native to Web SSO is currently available in Early Access. To use this feature, you must have an Enterprise plan. By using this feature, you agree to the applicable Free Trial terms in Okta’s Master Subscription Agreement. To learn more about Auth0’s product release cycle, read Product Release Stages.
Native to Web Single Sign-On (SSO) allows you to create a seamless, secure user experience between your native application and a web-based paid membership flow. Native to Web enables the native application to send the user’s authentication context to the web application using a short-lived, secure session_transfer_token.The sections below outline how you can add:
To your native application, a Subscribe Now button that lets authenticated users sign up for a paid membership plan using a secure web checkout experience.
To your web application, a Subscription page that allows user to select membership subscriptions without the user logging-in again.
This use case focuses on React-based web applications using the Auth0 React SDK.If you are using a different framework, such as Node or Express, the logic for managing session_transfer_token whether through a URL parameter or cookie can be adapted accordingly.
Enable Native to Web SSO in your native application
Native to Web SSO uses a session_transfer_token to establish SSO from a native to a web application. The session_transfer_token allows Auth0 to identify the user, the origin native application, and additional context securely. To learn more, read Native to Web SSO.Enable Native to Web SSO using Auth0 CLI:
If the session_transfer_token is injected into the browser with a cookie no additional changes to your web application are required. The only requirement is that the browser navigates to your application’s Login URI to handle the redirect of the user to your Auth0 tenant’s /authorize endpoint.
You can configure the Application Login URI in your application’s settings within the Auth0 Dashboard. This is the route Auth0 will redirect users to when initiating login from external sources.
Edit the file src/App.js and add a /join-membership route to the new subscription page:
Copy
Ask AI
import JoinMembership from "./views/JoinMembership"; {/* Redirect to the join membership page */}<Route path="/join-membership" component={JoinMembership} />
The new /join-membership route:
Determines if the user is authenticated. If not, it will redirect the user to the page.
If a session_transfer_token is appended as a URL parameter, the token is passed in the authentication request.
Once authenticated, the user will be presented with buttons to subscribe to different membership plans.
Run your React app and go to http://localhost:3000/join-membership
If the user is authenticated, the user will see the subscription options.
If the user is not authenticated, they are automatically redirected to the Auth0 Universal Login page.
If the URL includes a session_transfer_token, it will be included in the login request to Auth0.
If not, the login will proceed using the standard web authentication.
When the user logs in, the user is returned to the /join-membership page to select the subscription options.
Your native application needs to exchange the refresh_token for a session_transfer_token immediately before launching the web application. To do so, add the session transfer exchange and the web application launch logic inside the same event handler, an example is the button’s onClick method.
To launch the web-based subscription flow from your iOS native app, add a Subscribe to Membership button to the ProfileView.swift file.Edit the body of the ProfileView.swift file to include a button below the user information:
Copy
Ask AI
import SwiftUIstruct 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) } } }}
The ProfileView.swift file adds a Subscribe to Membership button and uses an onSubscribe closure to determine the behavior when selected.
Step 2: Implement the subscription flow using Native to Web SSO
Edit the MainView.swift file to define the behavior of the Subscribe to Membership button:
Copy
Ask AI
import SwiftUIimport Auth0import WebKitstruct MainView: View { @State var user: User? var body: some View { if let user = self.user { VStack { ProfileView(user: user, onSubscribe: launchSubscription) Button("Logout", action: self.logout) } } else { VStack { HeroView() Button("Login", action: self.login) } } } func login() { Auth0 .webAuth() .audience("https://sample.api.com") .scope("profile email offline_access openid") //.useHTTPS() // Use a Universal Link callback URL on 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("Credentials stored? \(credentials.refreshToken)") case .failure(let error): print("Failed with: \(error)") } } } func logout() { Auth0 .webAuth() .useHTTPS() .clearSession { result in switch result { case .success: self.user = nil case .failure(let error): print("Failed with: \(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}", // Replace with your actual Auth0 tenant domain .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("Failed to get SSO token: \(error)") } } case .failure(let error): print("Error loading credentials: \(error)") } } }}
This sample uses the audience https://sample.api.com for demonstration purposes. You can create an API with this identifier in your Auth0 tenant or replace it with your own API identifier.To learn more, read Set Up APIs.
This allows the user to select the Subscribe to Membership in the native app and immediately start the web application subscription process without logging in again.
To launch the web-based subscription flow from your Android native application, add a Subscribe to Membership button to the UI.Edit the MainActivity.kt file and add the following code to the onCreate() method:
This sample uses the audience https://sample.api.com for demonstration purposes. You can create an API with this identifier in your Auth0 tenant or replace it with your own API identifier.To learn more, read Set Up APIs.
Add the launchSubscriptionFlow() method to open the web application:
Copy
Ask AI
private fun launchSubscriptionFlow() { credentialsManager.getCredentials(object : Callback<Credentials, CredentialsManagerException> { override fun onSuccess(credentials: Credentials) { val refreshToken = credentials.refreshToken ?: return AuthenticationAPIClient(account) .ssoExchange(refreshToken) .start(object : Callback<SSOCredentials, AuthenticationException> { 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: AuthenticationException) { showSnackBar("Failed to get session transfer token: ${error.getDescription()}") } }) } override fun onFailure(error: CredentialsManagerException) { showSnackBar("Failed to load stored credentials: ${error.message}") } })}
This allows the user to select Subscribe to Membership in the native application and immediately start the web application subscription process without logging in again.
Once everything is configured, run your iOS or Android native application to log in, go to the Profile or to the Mainscreen and select the Subscribe to Membership button.The following takes place:
The stored refresh_token is used to request a secure session_transfer_token
The session_transfer_token is injected into a cookie for your Auth0 domain
A WKWebView is used to load your web application’s /join-membership route
The web application receives the session_transfer_token and completes login using Native to Web SSO
The user sees the subscription options immediately in the web application
You have created a seamless experience where a mobile native application user can launch a secure, authenticated flow in a web application without being prompted to log in again.
Explore more configuration options for Native to Web SSO: Dive deeper into session lifetime, rotation, device binding, and cascade revocation in the Native to Web SSO documentation.
Customize the post-login experience with Progressive Profiling: Use Auth0’s Progressive Profile Form to collect additional user data after login — such as plan preferences, address, or payment intent — before showing subscription options.