From dc6d22161cc2810fa4e026712d8e77545856eb76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Fri, 3 Jul 2026 13:02:28 +0200 Subject: [PATCH] fix(mobile): avoid stuck WebBrowser auth session on Android --- apps/mobile/src/lib/auth/use-device-auth.ts | 25 +++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/apps/mobile/src/lib/auth/use-device-auth.ts b/apps/mobile/src/lib/auth/use-device-auth.ts index 95bf0b9f71..3a6f05a187 100644 --- a/apps/mobile/src/lib/auth/use-device-auth.ts +++ b/apps/mobile/src/lib/auth/use-device-auth.ts @@ -1,5 +1,6 @@ import * as WebBrowser from 'expo-web-browser'; import { useCallback, useEffect, useRef, useState } from 'react'; +import { Platform } from 'react-native'; import { API_BASE_URL, WEB_BASE_URL } from '@/lib/config'; @@ -21,6 +22,16 @@ type DeviceAuthResult = DeviceAuthState & { const POLL_INTERVAL_MS = 3000; +// Android has no native auth session; expo-web-browser's polyfill keeps +// 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) { + await (Platform.OS === 'android' + ? WebBrowser.openBrowserAsync(url) + : WebBrowser.openAuthSessionAsync(url)); +} + export function useDeviceAuth(): DeviceAuthResult { const [state, setState] = useState({ status: 'idle', @@ -174,7 +185,7 @@ export function useDeviceAuth(): DeviceAuthResult { abortReference.current = abort; poll(data.code, abort); - await WebBrowser.openAuthSessionAsync(browserUrl); + await openAuthBrowser(browserUrl); } catch { setState({ status: 'error', @@ -201,7 +212,17 @@ export function useDeviceAuth(): DeviceAuthResult { const openBrowser = useCallback(async () => { if (state.verificationUrl) { - await WebBrowser.openAuthSessionAsync(state.verificationUrl); + try { + await openAuthBrowser(state.verificationUrl); + } catch { + setState(previous => ({ + status: 'error', + code: previous.code, + token: undefined, + error: 'Could not open browser. Please try again.', + verificationUrl: previous.verificationUrl, + })); + } } }, [state.verificationUrl]);