Skip to content

Conversation

@bhatganeshdarshan
Copy link

Description

This PR replaces the previous WebView-based login flow with Chrome Custom Tabs, improving reliability and UX across browsers

Fixes #6688

Why change from webview to custom tabs

  • WebView login can break or feel inconsistent when the flow opens external pages (email verification) and then returns to the app.
  • Custom Tabs uses the system browser context (cookies/session), which is generally more reliable

What changed

  • Replaced the in-app WebView login with Chrome Custom Tabs.
  • Updated manifest queries to detect Custom Tabs providers via CustomTabsService

- Replaced WebView-based OAuth with Chrome Custom Tabs for better security and user experience
- Added ChromeCustomTabLauncher to handle OAuth authorization in Chrome Custom Tabs
- Implemented OAuthCallbackHandler to capture OAuth callback deep links
- Implemented OAuthLoginCompleter to exchange authorization code for access token
- Updated MainActivity to handle OAuth callback deep links (streetcomplete://oauth)
- Modified LoginViewModel to use Chrome Custom Tabs instead of WebView
- Added androidx.browser:browser dependency for Custom Tabs support
- Configured deep link intent filter in AndroidManifest for OAuth callbacks
- Enhanced OAuth flow to properly include referer parameter for new user registrations
- Fixed issue where new users were not redirected to authorization page after email confirmation
This change improves the OAuth flow by:
1. Using Chrome Custom Tabs which shares cookies with the default browser
2. Providing better security than embedded WebViews
3. Ensuring new users see 'Continue authorization' button after email confirmation
4. Properly handling the OAuth callback with PKCE code challenge/verifier
- prevent Custom Tab relaunch on resume by tracking launch in ViewModel
- auto-reset login state if no OAuth callback received
- reset login state on back press from RequestingAuthorization
Comment on lines 219 to 220
// Chrome Custom Tabs for OAuth flow
implementation("androidx.browser:browser:1.9.0")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that's the big issue with this PR. This library is not multi platform. I cannot merge a PR that replaces functionality that already works with multiplatform (i.e. with iOS) with an implementation that doesn't.

Looking at the source code, it is also completely written in Java and also depends on a couple of Java and Android stuff ( https://android.googlesource.com/platform/frameworks/support/+/androidx-main/browser/browser/build.gradle#39 ), so it doesn't look like it would be trivial to migrate for them. I don't think it is on their agenda.

In short, we can't use that library.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only multiplatform way to open an URL in the browser via compose that I know is LocalUriHandler. This doesn't however, allow to pass any (launch) parameters to the browser.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect got it !! So if we dont want to use implementation("androidx.browser:browser:1.9.0") ,
we can open it in a browser without custom tabs ,

currently in my approach if chrome custom tabs are available , i m using that else it opens it in browser

so if we remove custom tabs and only open in browser like this :

fun launchUrl(context: Context, url: String): Boolean {
        return try {
            val browserIntent = Intent(Intent.ACTION_VIEW, url.toUri())
            context.startActivity(browserIntent)
            true
        } catch (e: Exception) {
            false
        }
    }

it'll work ig :

WhatsApp.Video.2026-01-17.at.19.03.36.mp4

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but Context is Android only and hence that will not even compile on platforms other than Android

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you said, the only way would be to use val uriHandler = LocalUriHandler.current right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a nutshell, yes.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That I know of, that is.

@westnordost
Copy link
Member

westnordost commented Jan 18, 2026

I haven't had a closer look at the code, it looks odd though that it is so much more code than with the WebView. Did you forget to delete code you copied or something? I'd think it should be less code when just calling the external browser + handling the URL callback because there's no fiddling around with the WebView.

Also, the WebView dependency can be removed.

I also spotted some things that seem to be residue from testing, such as delay, unrelated changes and the like.

Also, isn't there an entry in the manifest missing that declares that this app handles URLs with a certain scheme?

@bhatganeshdarshan
Copy link
Author

I haven't had a closer look at the code, it looks odd though that it is so much more code than with the WebView. Did you forget to delete code you copied or something? I'd think it should be less code when just calling the external browser + handling the URL callback because there's no fiddling around with the WebView.

Also, the WebView dependency can be removed.

I also spotted some things that seem to be residue from testing, such as delay, unrelated changes and the like.

Also, isn't there an entry in the manifest missing that declares that this app handles URLs with a certain scheme?

with webview we had the in-app control , errors ,redirects etc , also things like if user has presesed back and exited out of webview . But when launch external browser need to handle many cases like prevent reopening the browser , oauth callback and handling cancellation ..

so the ui code has reduced but the code related to the flow has become more explicit because we no longer control the browser like webview

and for entry in manifest , looks like everything working fine .. i removed the <query> which i was using to find the browsers that support custom tabs , since we no longer using custom tabs , its of no use so i removed it ..

also delay need to be removed , rename markCustomTabLaunched to a more relevent name like markAuthUrlLaunched and some Logs .. sorry i forgot to remove ..
lmk if any other changes need to be done
thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

New accounts redirect to OSM Home instead of Authorization page after email confirmation

2 participants