Checklist
Description
On Android, when authorize() (useAuth0) opens the login in a Chrome Custom Tab and the user minimizes the tab using the toolbar minimize button (the "Minimized Custom Tabs" / picture-in-picture feature, enabled by default since Chrome 122), the app returns to the foreground and the authorize() promise immediately rejects with a WebAuthError of code USER_CANCELLED (a0.session.user_cancelled).
The problem is that the Custom Tab is not closed — it stays alive in a floating/minimized window (a "zombie" browser). The user can re-open it and complete the Auth0 login in the browser, but the SDK has already rejected the promise and abandoned the transaction, so the eventual redirect is dropped and the credentials never reach the app. The result is an inconsistent state: the app believes the user cancelled and is unauthenticated, while the browser shows a successful (or completable) login.
Compounding this, cancelWebAuth() is a no-op on Android (the native A0Auth0Module implementation just resolves), so the app has no way to programmatically dismiss the zombie tab after the rejection either.
Expected behavior (any one of these would resolve it):
- Minimizing/backgrounding the Custom Tab should not be treated as a hard
USER_CANCELLED that abandons the transaction; the flow should be resumable when the user returns and completes login, or
- When the flow is cancelled, the Custom Tab should be dismissed/closed so it can't be resumed into a dead-end, or
cancelWebAuth() should be implemented on Android so the app can dismiss the tab and reconcile state, or
- Provide a way to opt out of the minimize button (e.g. via Auth Tab /
AuthTabIntent) for the web-auth flow.
Reproduction
Consistently reproducible on Android (Chrome ≥ 122 as the Custom Tabs provider):
- In a bare React Native app, call
const { authorize } = useAuth0() and invoke await authorize({ ... }).
- The Chrome Custom Tab opens with the Auth0 login page.
- Tap the minimize (down-arrow / PiP) button in the Custom Tab toolbar (or press Home and reopen the app).
- The app foregrounds and the
authorize() promise rejects with WebAuthError USER_CANCELLED (a0.session.user_cancelled).
- Observe that the Custom Tab is still alive (minimized PiP window / in recents). Re-open it and finish the login — the browser completes, but the app remains unauthenticated and the credentials are never delivered.
Additional context
- Native cause: the Android module rejects with
"a0.session.user_cancelled" in the error.isCanceled branch of the web-auth callback (android/.../A0Auth0Module.kt). The login uses the standard com.auth0.android.provider.WebAuthProvider Custom Tabs flow.
cancelWebAuth() / resumeWebAuth() are dummy implementations on Android in A0Auth0Module.kt ("only needed in iOS"), so the JS layer can't dismiss the tab after cancellation.
- The minimize button is Chrome's Minimized Custom Tabs feature (on by default since Chrome 122); there is no public
CustomTabsIntent API to hide just that button. Chrome's Auth Tab (AuthTabIntent, AndroidX Browser ≥ ~1.8) removes it, but the SDK still bundles androidx.browser:browser:1.2.0 and uses WebAuthProvider.
- Related Chromium/embedder context: minimize PiP keeps the Custom Tab task alive while the host app resumes, which is what triggers the resume-without-redirect cancellation.
- iOS is unaffected (uses
ASWebAuthenticationSession; cancelWebAuth() works there).
react-native-auth0 version
5.7.0 (also reproduces on 5.4.0)
React Native version
0.84.1
Expo version
N/A (bare React Native)
Platform
Android
Platform version(s)
Android 16 (API 36), Samsung SM-A156B (Galaxy A15 5G). Custom Tabs provider: Chrome 149.0.7827.197
Checklist
Description
On Android, when
authorize()(useAuth0) opens the login in a Chrome Custom Tab and the user minimizes the tab using the toolbar minimize button (the "Minimized Custom Tabs" / picture-in-picture feature, enabled by default since Chrome 122), the app returns to the foreground and theauthorize()promise immediately rejects with aWebAuthErrorof codeUSER_CANCELLED(a0.session.user_cancelled).The problem is that the Custom Tab is not closed — it stays alive in a floating/minimized window (a "zombie" browser). The user can re-open it and complete the Auth0 login in the browser, but the SDK has already rejected the promise and abandoned the transaction, so the eventual redirect is dropped and the credentials never reach the app. The result is an inconsistent state: the app believes the user cancelled and is unauthenticated, while the browser shows a successful (or completable) login.
Compounding this,
cancelWebAuth()is a no-op on Android (the nativeA0Auth0Moduleimplementation just resolves), so the app has no way to programmatically dismiss the zombie tab after the rejection either.Expected behavior (any one of these would resolve it):
USER_CANCELLEDthat abandons the transaction; the flow should be resumable when the user returns and completes login, orcancelWebAuth()should be implemented on Android so the app can dismiss the tab and reconcile state, orAuthTabIntent) for the web-auth flow.Reproduction
Consistently reproducible on Android (Chrome ≥ 122 as the Custom Tabs provider):
const { authorize } = useAuth0()and invokeawait authorize({ ... }).authorize()promise rejects withWebAuthErrorUSER_CANCELLED(a0.session.user_cancelled).Additional context
"a0.session.user_cancelled"in theerror.isCanceledbranch of the web-auth callback (android/.../A0Auth0Module.kt). The login uses the standardcom.auth0.android.provider.WebAuthProviderCustom Tabs flow.cancelWebAuth()/resumeWebAuth()are dummy implementations on Android inA0Auth0Module.kt("only needed in iOS"), so the JS layer can't dismiss the tab after cancellation.CustomTabsIntentAPI to hide just that button. Chrome's Auth Tab (AuthTabIntent, AndroidX Browser ≥ ~1.8) removes it, but the SDK still bundlesandroidx.browser:browser:1.2.0and usesWebAuthProvider.ASWebAuthenticationSession;cancelWebAuth()works there).react-native-auth0 version
5.7.0 (also reproduces on 5.4.0)
React Native version
0.84.1
Expo version
N/A (bare React Native)
Platform
Android
Platform version(s)
Android 16 (API 36), Samsung SM-A156B (Galaxy A15 5G). Custom Tabs provider: Chrome 149.0.7827.197