From eff72f5d8da63542e4786c700596d0b31cfbe728 Mon Sep 17 00:00:00 2001 From: ChrisCanin Date: Thu, 19 Mar 2026 09:39:57 -0700 Subject: [PATCH] fix(expo): dismiss browser after SSO/OAuth flow to prevent stuck sessions on re-login --- .changeset/fix-sso-browser-dismissal.md | 5 +++++ packages/expo/src/hooks/useOAuth.ts | 16 ++++++++++------ packages/expo/src/hooks/useSSO.ts | 19 ++++++++++++++----- 3 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 .changeset/fix-sso-browser-dismissal.md diff --git a/.changeset/fix-sso-browser-dismissal.md b/.changeset/fix-sso-browser-dismissal.md new file mode 100644 index 00000000000..f29d7ed67c8 --- /dev/null +++ b/.changeset/fix-sso-browser-dismissal.md @@ -0,0 +1,5 @@ +--- +'@clerk/expo': patch +--- + +Fix SSO/OAuth browser not being dismissed after authentication completes. On some platforms the in-app browser would remain open in the background after a successful flow, causing subsequent sign-in attempts to fail or appear frozen. `WebBrowser.dismissBrowser()` is now called unconditionally after `openAuthSessionAsync` resolves in both `useSSO` and `useOAuth`. diff --git a/packages/expo/src/hooks/useOAuth.ts b/packages/expo/src/hooks/useOAuth.ts index 80487ecf8ad..2ac5000bec9 100644 --- a/packages/expo/src/hooks/useOAuth.ts +++ b/packages/expo/src/hooks/useOAuth.ts @@ -77,13 +77,17 @@ export function useOAuth(useOAuthParams: UseOAuthFlowParams) { const { externalVerificationRedirectURL } = signIn.firstFactorVerification; - const authSessionResult = await WebBrowserModule.openAuthSessionAsync( - // @ts-ignore - externalVerificationRedirectURL.toString(), - oauthRedirectUrl, - ); + let authSessionResult: WebBrowser.WebBrowserAuthSessionResult; + try { + authSessionResult = await WebBrowserModule.openAuthSessionAsync( + // @ts-ignore + externalVerificationRedirectURL.toString(), + oauthRedirectUrl, + ); + } finally { + WebBrowserModule.dismissBrowser(); + } - // @ts-expect-error const { type, url } = authSessionResult || {}; // TODO: Check all the possible AuthSession results diff --git a/packages/expo/src/hooks/useSSO.ts b/packages/expo/src/hooks/useSSO.ts index 7dff8a208a2..d138324b653 100644 --- a/packages/expo/src/hooks/useSSO.ts +++ b/packages/expo/src/hooks/useSSO.ts @@ -86,11 +86,20 @@ export function useSSO() { return errorThrower.throw('Missing external verification redirect URL for SSO flow'); } - const authSessionResult = await WebBrowserModule.openAuthSessionAsync( - externalVerificationRedirectURL.toString(), - redirectUrl, - authSessionOptions, - ); + let authSessionResult: WebBrowser.WebBrowserAuthSessionResult; + try { + authSessionResult = await WebBrowserModule.openAuthSessionAsync( + externalVerificationRedirectURL.toString(), + redirectUrl, + authSessionOptions, + ); + } finally { + // Ensure the browser is always dismissed after the auth session completes or fails. + // Without this, the browser can remain open in the background on some platforms, + // causing subsequent SSO attempts to fail or the browser to appear frozen. + WebBrowserModule.dismissBrowser(); + } + if (authSessionResult.type !== 'success' || !authSessionResult.url) { return { createdSessionId: null,