feat: allow enabling EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER on the Custom Tab intent - #1065
Conversation
…stom Tab intent Adds CustomTabsOptions.Builder#withSendToExternalDefaultHandlerEnabled(boolean). When enabled, toIntent() sets CustomTabsIntent.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER so that the initial navigation chain of the Custom Tab may leave the browser and launch the app. This lets https (App Links) callbacks reach the app on Chrome versions prior to 120 when /authorize redirects straight to the callback URL without user interaction (existing session, prompt=none). Disabled by default.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review. 📝 WalkthroughWalkthrough
ChangesExternal handler option
Estimated code review effort: 2 (Simple) | ~10 minutes Merge Risk: 🔵 Low · up to The opt-in can route HTTPS authentication callbacks to an unintended or unavailable app if verified App Links are not correctly configured, while existing validation limits unauthorized session or token use and default behavior remains unchanged. The PR is mergeable with explicit owner awareness to document the verified-link requirement and confirm compatibility expectations for serialized options. Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant Builder
participant CustomTabsOptions
participant CustomTabsIntent
Builder->>CustomTabsOptions: build with external handler enabled
CustomTabsOptions->>CustomTabsIntent: set external handler flag
CustomTabsIntent-->>CustomTabsOptions: report enabled flag
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Hi @jishidaaaaa , thanks for raising this PR. We will review this |
Changes
When
WebAuthProvideropens Universal Login in a Custom Tab, the Custom Tabs intent always targets the browser package explicitly (a Custom Tabs session implies it). Chrome interprets an intent that explicitly targets the browser as "the app wants to stay in the browser" and refuses to hand off redirects that happen in the initial navigation chain to another app, unless it trusts the calling app.Until Chrome 120 (December 2023) that trust was only granted to Google-signed apps. On Chrome <= 119, when
/authorizeimmediately 302-redirects to anhttpscallback URL (Android App Links) — for example because the user already has an Auth0 session, orprompt=noneis used — Chrome loads the callback URL inside the Custom Tab instead of launching the app. The tenant answers404 Not found., which is what the user sees. Flows that involve user input (typing credentials) are not affected, because the input starts a new navigation chain with a user gesture.Chrome has provided an opt-in escape hatch for exactly this case since Chrome 84:
CustomTabsIntent.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER. The androidx.browser javadoc describes it as: "A Custom Tab Intent from a Custom Tab session will always have the package set, so the Intent will always be to the browser. This extra can be used to allow the initial Intent navigation chain to leave the browser."CustomTabsOptionscurrently offers no way to set it.This PR adds:
CustomTabsOptions.Builder#withSendToExternalDefaultHandlerEnabled(boolean)(public API, defaultfalse, opt-in).CustomTabsOptions#toIntentcallsCustomTabsIntent.Builder#setSendToExternalDefaultHandlerEnabled(true).toBuilder()round-trip support for the new flag.Behavior is unchanged unless the option is enabled. The Auth Tab and TWA paths are not touched (Auth Tab handles the redirect itself; TWA is out of scope). The androidx.browser API used is available in the version already declared by the library (1.10.0).
Usage:
References
CustomTabsIntent#EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER,CustomTabsIntent.Builder#setSendToExternalDefaultHandlerEnabledcomponents/external_intents/.../RedirectHandler.java:if (isCustomTabIntent && sendToExternalApps) preferToStayInChrome = false;(present since Chrome 84)ExternalNavigationHandler.java: the "Launching intent explicitly targeted the browser." branch keeps http(s) redirects inside the browserchrome/.../customtabs/CustomTabDelegateFactory.java:isForTrustedCallingApprequiredisGoogleSigned(mClientPackageName)up to Chrome 119; gated byTrustedClientGestureBypass(enabled by default) from Chrome 120; unconditional from Chrome 136Testing
Unit tests added to
CustomTabsOptionsTest:toBuilder()(copyWithEphemeralBrowsing())I could not run the Gradle test suite locally (no Android SDK on the machine used for this change), so I am relying on this repository's CI for the unit tests and lint. The androidx.browser APIs used (
Builder#setSendToExternalDefaultHandlerEnabled,CustomTabsIntent#isSendToExternalDefaultHandlerEnabled,EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER) were verified to exist in thebrowser:1.10.0artifact the library already depends on.How to reproduce the underlying problem and verify the fix on a device:
auth0Scheme = "https"and verified Android App Links, on a device running Chrome <= 119.prompt=none.WebAuthProvider.login(...). Without the option,/authorizeredirects straight to the callback URL and the Custom Tab showsNot found.. WithwithSendToExternalDefaultHandlerEnabled(true), the app receives the callback.Checklist
Summary by CodeRabbit
New Features
Bug Fixes