fix(mobile): avoid stuck WebBrowser auth session on Android - #4376
Conversation
| // module-level state that can get stuck and reject every future call | ||
| // (KILO-APP-22). We poll the server for approval instead of relying on a | ||
| // redirect, so a plain browser open is all Android needs. | ||
| async function openAuthBrowser(url: string) { |
There was a problem hiding this comment.
WARNING: Android now opens the browser with openBrowserAsync, but approval still dismisses via dismissAuthSession()
WebBrowser.dismissAuthSession() only affects sessions started with openAuthSessionAsync; it has no effect on a browser opened with openBrowserAsync. Since Android now goes through openBrowserAsync in both start() and openBrowser(), the tab opened on Android will no longer auto-close when polling detects approval (the case 200: branch in poll() still calls WebBrowser.dismissAuthSession()). The user will have to manually switch back to the app after approving sign-in on Android. Consider calling WebBrowser.dismissBrowser() on Android in that success path as well.
Reply with @kilocode-bot fix it to have Kilo Code address this issue.
There was a problem hiding this comment.
Checked against expo-web-browser 55.0.16 source: the Android native module (WebBrowserModule.kt) implements no dismissal at all — no dismissBrowser, no dismissAuthSession. Custom tabs can't be closed programmatically; return-to-app is handled by BrowserProxyActivity when the user closes the tab. dismissAuthSession() on Android has always taken the JS fallback branch targeting ExponentWebBrowser.dismissBrowser, which doesn't exist there — so the tab never auto-closed on Android before this PR either, and dismissBrowser() (ExponentWebBrowser.dismissBrowser?.()) would be a no-op. No regression.
The valid part: with Android no longer opening an auth session, the unconditional dismissAuthSession() in poll() is pointless there and a latent UnavailabilityError throw site inside the poll's try block. Follow-up guards it to iOS: #4377
Code Review SummaryStatus: 1 Issue Found | Recommendation: Address before merge Executive SummaryOn Android, the new Overview
Issue Details (click to expand)WARNING
Files Reviewed (1 file)
Fix these issues in Kilo Cloud Reviewed by claude-sonnet-5-20260630 · Input: 24 · Output: 12.1K · Cached: 576.2K Review guidance: REVIEW.md from base branch |
Summary
Fixes Sentry issue KILO-APP-22: on Android, sign-in could permanently fail with
The WebBrowser's auth session is in an invalid state with a redirect handler set when it should not beuntil the app was restarted.Fixes KILO-APP-22
Mechanism
Android has no native auth session, so expo-web-browser's
openAuthSessionAsyncfalls back to a JS polyfill that keeps module-level state (_redirectSubscription,_onWebBrowserCloseAndroid). The polyfill only resolves on an AppStateactivetransition and swallows the first AppState event after module load, so a session can get stuck unresolved — after which every subsequentopenAuthSessionAsynccall throws, making sign-in impossible.Fix
We never rely on the redirect deep-link on Android — the app polls the server for device-auth approval. So on Android we bypass the broken polyfill entirely and use
WebBrowser.openBrowserAsyncinstead (newopenAuthBrowserhelper used by bothstart()andopenBrowser()). Also added error handling toopenBrowser(), which previously surfaced throws as unhandled rejections; it now sets an error state with a user-visible message.