[GH-ISSUE #8407] [BUG] [Expo] linkSocial does not use openAuthSessionAsync on Android (works on iOS) #28402

Closed
opened 2026-04-17 19:51:39 -05:00 by GiteaMirror · 17 comments
Owner

Originally created by @PierrickViot-Launier on GitHub (Mar 5, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/8407

Is this suited for github?

  • Yes, this is suited for github

To Reproduce

  1. Set up Better Auth with Expo using @better-auth/expo client plugin with a custom scheme (e.g., myapp)
  2. Configure a social provider (Facebook) with socialProviders.facebook on the server
  3. Configure account.accountLinking with trustedProviders: ['facebook']
  4. On a logged-in user, call authClient.linkSocial({ provider: 'facebook', callbackURL: '/auth/callback' })
  5. Test on both iOS and Android

On iOS: an in-app Safari overlay (ASWebAuthenticationSession) opens, completes OAuth, closes, and returns to the app cleanly.

On Android: the system browser (Chrome Custom Tabs) opens instead of an in-app browser. After OAuth completes, the callback deep link (invi://auth/callback) is sent back to the app as a regular deep link, which crashes React Navigation because it tries to resolve an unknown route.

Current vs. Expected behavior

Current (Android): authClient.linkSocial() opens the system browser/Chrome Custom Tabs. After the OAuth flow completes, the callback deep link reaches React Navigation and causes a crash (Cannot read property 'status' of undefined at useNavigation()). The account linking itself succeeds (verified in DB), but the app crashes on return.

Expected: authClient.linkSocial() should use WebBrowser.openAuthSessionAsync on Android (same as iOS), so the callback URL is consumed internally by the in-app browser and the app returns cleanly without triggering deep link handling in React Navigation.

Note: PR #4420 fixed this for iOS but the fix does not appear to work on Android.

What version of Better Auth are you using?

1.5.3

System info

- better-auth: 1.5.3
- @better-auth/expo: 1.5.3
- expo: SDK 53
- react-native: 0.79
- @react-navigation/native: 7.1.11
- expo-web-browser: latest
- Tested on: Android physical device (development build)
- iOS: works correctly (in-app Safari overlay)

Which area(s) are affected? (Select all that apply)

Client

Auth config (if applicable)

// Server
export const auth = betterAuth({
    baseURL: process.env.API_BASE_URL,
    database: drizzleAdapter(db, { provider: 'pg', schema }),
    emailAndPassword: { enabled: true },
    socialProviders: {
        facebook: {
            clientId: process.env.FB_CLIENT_ID,
            clientSecret: process.env.FB_APP_SECRET,
            disableImplicitSignUp: true,
        },
    },
    plugins: [expo()],
    account: {
        accountLinking: {
            enabled: true,
            trustedProviders: ['facebook'],
        },
    },
    trustedOrigins: ['myapp://'],
});


// Client
export const authClient = createAuthClient({
    baseURL: API_URL,
    plugins: [
        expoClient({
            scheme: 'myapp',
            storagePrefix: 'myapp',
            storage: SecureStore,
        }),
    ],
});

Additional context

PR #4420 (merged Sept 2025) added linkSocial redirect handling to the Expo plugin. This fix works on iOS — linkSocial correctly uses ASWebAuthenticationSession (in-app Safari overlay) and the callback is consumed internally. On Android, the same code path appears to open Chrome Custom Tabs via the system browser instead of openAuthSessionAsync, causing the callback deep link to reach the app's navigation layer.

The original issue requesting this fix was #3607.

Originally created by @PierrickViot-Launier on GitHub (Mar 5, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/8407 ### Is this suited for github? - [x] Yes, this is suited for github ### To Reproduce 1. Set up Better Auth with Expo using `@better-auth/expo` client plugin with a custom scheme (e.g., `myapp`) 2. Configure a social provider (Facebook) with `socialProviders.facebook` on the server 3. Configure `account.accountLinking` with `trustedProviders: ['facebook']` 4. On a logged-in user, call `authClient.linkSocial({ provider: 'facebook', callbackURL: '/auth/callback' })` 5. Test on both iOS and Android On iOS: an in-app Safari overlay (ASWebAuthenticationSession) opens, completes OAuth, closes, and returns to the app cleanly. On Android: the system browser (Chrome Custom Tabs) opens instead of an in-app browser. After OAuth completes, the callback deep link (`invi://auth/callback`) is sent back to the app as a regular deep link, which crashes React Navigation because it tries to resolve an unknown route. ### Current vs. Expected behavior **Current (Android):** `authClient.linkSocial()` opens the system browser/Chrome Custom Tabs. After the OAuth flow completes, the callback deep link reaches React Navigation and causes a crash (`Cannot read property 'status' of undefined` at `useNavigation()`). The account linking itself succeeds (verified in DB), but the app crashes on return. **Expected:** `authClient.linkSocial()` should use `WebBrowser.openAuthSessionAsync` on Android (same as iOS), so the callback URL is consumed internally by the in-app browser and the app returns cleanly without triggering deep link handling in React Navigation. **Note:** PR #4420 fixed this for iOS but the fix does not appear to work on Android. ### What version of Better Auth are you using? 1.5.3 ### System info ```bash - better-auth: 1.5.3 - @better-auth/expo: 1.5.3 - expo: SDK 53 - react-native: 0.79 - @react-navigation/native: 7.1.11 - expo-web-browser: latest - Tested on: Android physical device (development build) - iOS: works correctly (in-app Safari overlay) ``` ### Which area(s) are affected? (Select all that apply) Client ### Auth config (if applicable) ```typescript // Server export const auth = betterAuth({ baseURL: process.env.API_BASE_URL, database: drizzleAdapter(db, { provider: 'pg', schema }), emailAndPassword: { enabled: true }, socialProviders: { facebook: { clientId: process.env.FB_CLIENT_ID, clientSecret: process.env.FB_APP_SECRET, disableImplicitSignUp: true, }, }, plugins: [expo()], account: { accountLinking: { enabled: true, trustedProviders: ['facebook'], }, }, trustedOrigins: ['myapp://'], }); // Client export const authClient = createAuthClient({ baseURL: API_URL, plugins: [ expoClient({ scheme: 'myapp', storagePrefix: 'myapp', storage: SecureStore, }), ], }); ``` ### Additional context PR #4420 (merged Sept 2025) added linkSocial redirect handling to the Expo plugin. This fix works on iOS — linkSocial correctly uses ASWebAuthenticationSession (in-app Safari overlay) and the callback is consumed internally. On Android, the same code path appears to open Chrome Custom Tabs via the system browser instead of openAuthSessionAsync, causing the callback deep link to reach the app's navigation layer. The original issue requesting this fix was #3607.
GiteaMirror added the lockedbug labels 2026-04-17 19:51:39 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Mar 5, 2026):

Hi @PierrickViot-Launier! I'm Dosu and I’m helping the better-auth team.

Looking at the Expo client plugin source code, both iOS and Android use the same WebBrowser.openAuthSessionAsync call for linkSocial. There's no code path that intentionally opens the system browser on Android instead.

The only Android-specific code is a dismissAuthSession() call before opening new sessions (added in PR #6388), but this shouldn't cause system browser behavior.

A few things to investigate:

  1. Verify openAuthSessionAsync is actually being called – Add debug logging to confirm the code path is executing. If it's not reaching the in-app browser call, something may be failing silently.

  2. Try passing showInRecents: true in webBrowserOptions – This has helped with other Android OAuth issues where the browser window behaves unexpectedly.

  3. Check for expo-web-browser state issuesIssue #6368 documents cases where Android's session state gets corrupted between OAuth attempts.

  4. Deep link configuration – Your callback URL scheme (invi://) setup in android/app.json or AndroidManifest.xml may affect how Chrome Custom Tabs handles the redirect.

Could you share your webBrowserOptions configuration (if any) and confirm whether this is the first linkSocial attempt or a subsequent one? Also, does regular signIn.social() work correctly with the in-app browser on Android?

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:4002209315 --> @dosubot[bot] commented on GitHub (Mar 5, 2026): <!-- Greeting --> Hi @PierrickViot-Launier! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the better-auth team. <!-- Answer --> Looking at the [Expo client plugin source code](https://github.com/better-auth/better-auth/blob/b34e200513b23d9fb913698173cd408f01f63f9c/packages/expo/src/client.ts#L350-L407), **both iOS and Android use the same `WebBrowser.openAuthSessionAsync` call** for `linkSocial`. There's no code path that intentionally opens the system browser on Android instead. The only Android-specific code is [a `dismissAuthSession()` call before opening new sessions](https://github.com/better-auth/better-auth/blob/b34e200513b23d9fb913698173cd408f01f63f9c/packages/expo/src/client.ts#L376-L380) (added in [PR #6388](https://github.com/better-auth/better-auth/pull/6388)), but this shouldn't cause system browser behavior. A few things to investigate: 1. **Verify `openAuthSessionAsync` is actually being called** – Add debug logging to confirm the code path is executing. If it's not reaching the in-app browser call, something may be failing silently. 2. **Try passing `showInRecents: true`** in `webBrowserOptions` – This has helped with [other Android OAuth issues](https://github.com/better-auth/better-auth/issues/1447) where the browser window behaves unexpectedly. 3. **Check for expo-web-browser state issues** – [Issue #6368](https://github.com/better-auth/better-auth/issues/6368) documents cases where Android's session state gets corrupted between OAuth attempts. 4. **Deep link configuration** – Your callback URL scheme (`invi://`) setup in `android/app.json` or `AndroidManifest.xml` may affect how Chrome Custom Tabs handles the redirect. Could you share your `webBrowserOptions` configuration (if any) and confirm whether this is the first `linkSocial` attempt or a subsequent one? Also, does regular `signIn.social()` work correctly with the in-app browser on Android? <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/59381b92-6408-435c-9732-edfbad9d9d22?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/59381b92-6408-435c-9732-edfbad9d9d22?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/59381b92-6408-435c-9732-edfbad9d9d22?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/59381b92-6408-435c-9732-edfbad9d9d22?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/59381b92-6408-435c-9732-edfbad9d9d22?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/59381b92-6408-435c-9732-edfbad9d9d22?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/59381b92-6408-435c-9732-edfbad9d9d22?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Looking%20at%20the%20%5BExpo%20client%20plugin%20source%20code%5D%28https%3A//github.com/better-auth/better-auth/blob/b34e200513b23d9fb913698173cd408f01f63f9c/packages/expo/src/client.ts%23L350-L407%29%2C%20%2A%2Aboth%20iOS%20and%20Android%20use%20the%20same%20%60WebBrowser.openAuthSessionAsync%60%20call%2A%2A%20for%20%60linkSocial%60.%20There%27s%20no%20code%20path%20that%20intentionally%20opens%20the%20system%20browser%20on%20Android%20instead.%0A%0AThe%20only%20Android-specific%20code%20is%20%5Ba%20%60dismissAuthSession%28%29%60%20call%20before%20opening%20new%20sessions%5D%28https%3A//github.com/better-auth/better-auth/blob/b34e200513b23d9fb913698173cd408f01f63f9c/packages/expo/src/client.ts%23L376-L380%29%20%28added%20in%20%5BPR%20%236388%5D%28https%3A//github.com/better-auth/better-auth/pull/6388%29%29%2C%20but%20this%20shouldn%27t%20cause%20system%20browser%20behavior.%0A%0AA%20few%20things%20to%20investigate%3A%0A%0A1.%20%2A%2AVerify%20%60openAuthSessionAsync%60%20is%20actually%20being%20called%2A%2A%20%E2%80%93%20Add%20debug%20logging%20to%20confirm%20the%20code%20path%20is%20executing.%20If%20it%27s%20not%20reaching%20the%20in-app%20browser%20call%2C%20something%20may%20be%20failing%20silently.%0A%0A2.%20%2A%2ATry%20passing%20%60showInRecents%3A%20true%60%2A%2A%20in%20%60webBrowserOptions%60%20%E2%80%93%20This%20has%20helped%20with%20%5Bother%20Android%20OAuth%20issues%5D%28https%3A//github.com/better-auth/better-auth/issues/1447%29%20where%20the%20browser%20window%20behaves%20unexpectedly.%0A%0A3.%20%2A%2ACheck%20for%20expo-web-browser%20state%20issues%2A%2A%20%E2%80%93%20%5BIssue%20%236368%5D%28https%3A//github.com/better-auth/better-auth/issues/6368%29%20documents%20cases%20where%20Android%27s%20session%20state%20gets%20corrupted%20between%20OAuth%20attempts.%0A%0A4.%20%2A%2ADeep%20link%20configuration%2A%2A%20%E2%80%93%20Your%20callback%20URL%20scheme%20%28%60invi%3A//%60%29%20setup%20in%20%60android/app.json%60%20or%20%60AndroidManifest.xml%60%20may%20affect%20how%20Chrome%20Custom%20Tabs%20handles%20the%20redirect.%0A%0ACould%20you%20share%20your%20%60webBrowserOptions%60%20configuration%20%28if%20any%29%20and%20confirm%20whether%20this%20is%20the%20first%20%60linkSocial%60%20attempt%20or%20a%20subsequent%20one%3F%20Also%2C%20does%20regular%20%60signIn.social%28%29%60%20work%20correctly%20with%20the%20in-app%20browser%20on%20Android%3F)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8407)
Author
Owner

@PierrickViot-Launier commented on GitHub (Mar 5, 2026):

@dosu

Thanks for the suggestions. Here's what I found:

  1. openAuthSessionAsync is being called, but opens the full Chrome app instead of a Chrome Custom Tab overlay.

I tested WebBrowser.openAuthSessionAsync directly (bypassing Better Auth entirely):

const result = await WebBrowser.openAuthSessionAsync(
    'https://www.google.com',
    'invi://auth/callback',
);

console.log('Browser result:', result);

This opens the full Chrome app (switches away from my app entirely), not a Chrome Custom Tab overlay. Returns {"type": "dismiss"} when I navigate back. This happens even with Chrome set as the default browser. So the issue is at the expo-web-browser level, not specific to Better Auth's Expo plugin.

On iOS, the same openAuthSessionAsync call correctly opens an in-app Safari overlay (ASWebAuthenticationSession).

  1. showInRecents: true — no change. Same behavior with:
expoClient({
    scheme: 'invi',
    storagePrefix: 'invi',
    storage: SecureStore,
    webBrowserOptions: {
        showInRecents: true,
    },
})
  1. This is the first linkSocial attempt on a fresh app install. Not a subsequent attempt issue.

  2. signIn.social() also opens the full Chrome app on Android — same behavior as linkSocial. So this is not specific to linkSocial.

<!-- gh-comment-id:4002365550 --> @PierrickViot-Launier commented on GitHub (Mar 5, 2026): @dosu Thanks for the suggestions. Here's what I found: 1. openAuthSessionAsync is being called, but opens the full Chrome app instead of a Chrome Custom Tab overlay. I tested WebBrowser.openAuthSessionAsync directly (bypassing Better Auth entirely): ``` const result = await WebBrowser.openAuthSessionAsync( 'https://www.google.com', 'invi://auth/callback', ); console.log('Browser result:', result); ``` This opens the full Chrome app (switches away from my app entirely), not a Chrome Custom Tab overlay. Returns `{"type": "dismiss"}` when I navigate back. This happens even with Chrome set as the default browser. So the issue is at the expo-web-browser level, not specific to Better Auth's Expo plugin. On iOS, the same openAuthSessionAsync call correctly opens an in-app Safari overlay (ASWebAuthenticationSession). 2. showInRecents: true — no change. Same behavior with: ``` expoClient({ scheme: 'invi', storagePrefix: 'invi', storage: SecureStore, webBrowserOptions: { showInRecents: true, }, }) ``` 3. This is the first linkSocial attempt on a fresh app install. Not a subsequent attempt issue. 4. `signIn.social()` also opens the full Chrome app on Android — same behavior as linkSocial. So this is not specific to linkSocial.
Author
Owner

@dosubot[bot] commented on GitHub (Mar 5, 2026):

Thanks for the thorough debugging! Your test confirms this is an expo-web-browser issue, not a Better Auth issue. Better Auth's Expo plugin simply passes through to WebBrowser.openAuthSessionAsync with no custom browser logic.

The behavior you're seeing (full Chrome app instead of Chrome Custom Tab) is a known expo-web-browser behavior on Android. A few things to check:

  1. Expo SDK 53 compatibility – There have been reports of openAuthSessionAsync behavior changes across SDK versions. You might try testing with WebBrowser.openBrowserAsync to see if it opens a Custom Tab (it should), which would confirm the issue is specific to openAuthSessionAsync.

  2. Device/Chrome version – Some Android devices or older Chrome versions don't properly support openAuthSessionAsync with Custom Tabs. This can vary by manufacturer.

  3. Try createTask: false – Pass this in webBrowserOptions:

    webBrowserOptions: {
        createTask: false,
    }
    

I'd recommend opening an issue on the expo/expo repository since this is expo-web-browser behavior. Include your Expo SDK version (53), Android device info, and Chrome version. The Expo team would be best positioned to help diagnose why openAuthSessionAsync isn't using Chrome Custom Tabs on your device.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:4002382629 --> @dosubot[bot] commented on GitHub (Mar 5, 2026): <!-- Answer --> Thanks for the thorough debugging! Your test confirms this is an **expo-web-browser issue**, not a Better Auth issue. Better Auth's Expo plugin [simply passes through to `WebBrowser.openAuthSessionAsync`](https://github.com/better-auth/better-auth/blob/b34e200513b23d9fb913698173cd408f01f63f9c/packages/expo/src/client.ts#L394-L398) with no custom browser logic. The behavior you're seeing (full Chrome app instead of Chrome Custom Tab) is a known expo-web-browser behavior on Android. A few things to check: 1. **Expo SDK 53 compatibility** – There have been reports of `openAuthSessionAsync` behavior changes across SDK versions. You might try testing with `WebBrowser.openBrowserAsync` to see if it opens a Custom Tab (it should), which would confirm the issue is specific to `openAuthSessionAsync`. 2. **Device/Chrome version** – Some Android devices or older Chrome versions don't properly support `openAuthSessionAsync` with Custom Tabs. This can vary by manufacturer. 3. **Try `createTask: false`** – Pass this in `webBrowserOptions`: ```typescript webBrowserOptions: { createTask: false, } ``` I'd recommend opening an issue on the [expo/expo repository](https://github.com/expo/expo) since this is expo-web-browser behavior. Include your Expo SDK version (53), Android device info, and Chrome version. The Expo team would be best positioned to help diagnose why `openAuthSessionAsync` isn't using Chrome Custom Tabs on your device. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/f7e94ae5-e2c0-4dee-b705-949b91ce5c20?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/f7e94ae5-e2c0-4dee-b705-949b91ce5c20?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/f7e94ae5-e2c0-4dee-b705-949b91ce5c20?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/f7e94ae5-e2c0-4dee-b705-949b91ce5c20?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/f7e94ae5-e2c0-4dee-b705-949b91ce5c20?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/f7e94ae5-e2c0-4dee-b705-949b91ce5c20?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/f7e94ae5-e2c0-4dee-b705-949b91ce5c20?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Thanks%20for%20the%20thorough%20debugging%21%20Your%20test%20confirms%20this%20is%20an%20%2A%2Aexpo-web-browser%20issue%2A%2A%2C%20not%20a%20Better%20Auth%20issue.%20Better%20Auth%27s%20Expo%20plugin%20%5Bsimply%20passes%20through%20to%20%60WebBrowser.openAuthSessionAsync%60%5D%28https%3A//github.com/better-auth/better-auth/blob/b34e200513b23d9fb913698173cd408f01f63f9c/packages/expo/src/client.ts%23L394-L398%29%20with%20no%20custom%20browser%20logic.%0A%0AThe%20behavior%20you%27re%20seeing%20%28full%20Chrome%20app%20instead%20of%20Chrome%20Custom%20Tab%29%20is%20a%20known%20expo-web-browser%20behavior%20on%20Android.%20A%20few%20things%20to%20check%3A%0A%0A1.%20%2A%2AExpo%20SDK%2053%20compatibility%2A%2A%20%E2%80%93%20There%20have%20been%20reports%20of%20%60openAuthSessionAsync%60%20behavior%20changes%20across%20SDK%20versions.%20You%20might%20try%20testing%20with%20%60WebBrowser.openBrowserAsync%60%20to%20see%20if%20it%20opens%20a%20Custom%20Tab%20%28it%20should%29%2C%20which%20would%20confirm%20the%20issue%20is%20specific%20to%20%60openAuthSessionAsync%60.%0A%0A2.%20%2A%2ADevice/Chrome%20version%2A%2A%20%E2%80%93%20Some%20Android%20devices%20or%20older%20Chrome%20versions%20don%27t%20properly%20support%20%60openAuthSessionAsync%60%20with%20Custom%20Tabs.%20This%20can%20vary%20by%20manufacturer.%0A%0A3.%20%2A%2ATry%20%60createTask%3A%20false%60%2A%2A%20%E2%80%93%20Pass%20this%20in%20%60webBrowserOptions%60%3A%0A%20%20%20%60%60%60typescript%0A%20%20%20webBrowserOptions%3A%20%7B%0A%20%20%20%20%20%20%20createTask%3A%20false%2C%0A%20%20%20%7D%0A%20%20%20%60%60%60%0A%0AI%27d%20recommend%20opening%20an%20issue%20on%20the%20%5Bexpo/expo%20repository%5D%28https%3A//github.com/expo/expo%29%20since%20this%20is%20expo-web-browser%20behavior.%20Include%20your%20Expo%20SDK%20version%20%2853%29%2C%20Android%20device%20info%2C%20and%20Chrome%20version.%20The%20Expo%20team%20would%20be%20best%20positioned%20to%20help%20diagnose%20why%20%60openAuthSessionAsync%60%20isn%27t%20using%20Chrome%20Custom%20Tabs%20on%20your%20device.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8407)
Author
Owner

@PierrickViot-Launier commented on GitHub (Mar 5, 2026):

@dosu

Update: I logged the response from authClient.linkSocial() and it returns:

{"data": {"redirect": true, "url": "https://www.facebook.com/v24.0/dialog/oauth?..."}, "error": null}

The Expo plugin is not intercepting the redirect response. It returns the OAuth URL as data instead of opening it with openAuthSessionAsync. This happens on both a physical Samsung S21 and the Android emulator.

I also tested WebBrowser.openAuthSessionAsync directly — it works and opens the browser. So the issue is specifically that the Expo plugin's redirect interception isn't triggering for the /link-social endpoint.

<!-- gh-comment-id:4002517164 --> @PierrickViot-Launier commented on GitHub (Mar 5, 2026): @dosu Update: I logged the response from authClient.linkSocial() and it returns: `{"data": {"redirect": true, "url": "https://www.facebook.com/v24.0/dialog/oauth?..."}, "error": null}` The Expo plugin is not intercepting the redirect response. It returns the OAuth URL as data instead of opening it with openAuthSessionAsync. This happens on both a physical Samsung S21 and the Android emulator. I also tested WebBrowser.openAuthSessionAsync directly — it works and opens the browser. So the issue is specifically that the Expo plugin's redirect interception isn't triggering for the /link-social endpoint.
Author
Owner

@dosubot[bot] commented on GitHub (Mar 5, 2026):

Great debugging! This pinpoints the issue. The Expo plugin's redirect interception checks these conditions in the onSuccess hook:

if (
    context.data?.redirect &&
    (context.request.url.toString().includes("/sign-in") ||
        context.request.url.toString().includes("/link-social")) &&
    !context.request?.body.includes("idToken")
)

Since you're getting {redirect: true, url: "..."} back, the interception isn't triggering. Could you log what context.request.url.toString() resolves to? The URL string check uses includes("/link-social") — if the actual request URL doesn't contain that exact string (e.g., different casing, different path structure), the interception would fail.

Also verify:

  1. What endpoint URL is actually being called? The linkSocial() client method should hit something like /api/auth/link-social/facebook
  2. Is the request body including idToken? That would bypass interception

This looks like either the URL path doesn't match the expected pattern, or there's something in the request causing it to skip the browser opening logic. If you can share the full context.request.url value when linkSocial is called, that would help identify where the mismatch is.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:4002533137 --> @dosubot[bot] commented on GitHub (Mar 5, 2026): <!-- Answer --> Great debugging! This pinpoints the issue. The Expo plugin's redirect interception checks [these conditions in the `onSuccess` hook](https://github.com/better-auth/better-auth/blob/c15f6d9c0addd4218077f38c13be51cc17b69b42/packages/expo/src/client.ts#L350-L355): ```typescript if ( context.data?.redirect && (context.request.url.toString().includes("/sign-in") || context.request.url.toString().includes("/link-social")) && !context.request?.body.includes("idToken") ) ``` Since you're getting `{redirect: true, url: "..."}` back, the interception isn't triggering. Could you log what `context.request.url.toString()` resolves to? The URL string check uses `includes("/link-social")` — if the actual request URL doesn't contain that exact string (e.g., different casing, different path structure), the interception would fail. Also verify: 1. **What endpoint URL is actually being called?** The `linkSocial()` client method should hit something like `/api/auth/link-social/facebook` 2. **Is the request body including `idToken`?** That would bypass interception This looks like either the URL path doesn't match the expected pattern, or there's something in the request causing it to skip the browser opening logic. If you can share the full `context.request.url` value when `linkSocial` is called, that would help identify where the mismatch is. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/72a390b8-7f49-404b-a9bb-dea8168efa02?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/72a390b8-7f49-404b-a9bb-dea8168efa02?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/72a390b8-7f49-404b-a9bb-dea8168efa02?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/72a390b8-7f49-404b-a9bb-dea8168efa02?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/72a390b8-7f49-404b-a9bb-dea8168efa02?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/72a390b8-7f49-404b-a9bb-dea8168efa02?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/72a390b8-7f49-404b-a9bb-dea8168efa02?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Great%20debugging%21%20This%20pinpoints%20the%20issue.%20The%20Expo%20plugin%27s%20redirect%20interception%20checks%20%5Bthese%20conditions%20in%20the%20%60onSuccess%60%20hook%5D%28https%3A//github.com/better-auth/better-auth/blob/c15f6d9c0addd4218077f38c13be51cc17b69b42/packages/expo/src/client.ts%23L350-L355%29%3A%0A%0A%60%60%60typescript%0Aif%20%28%0A%20%20%20%20context.data%3F.redirect%20%26%26%0A%20%20%20%20%28context.request.url.toString%28%29.includes%28%22/sign-in%22%29%20%7C%7C%0A%20%20%20%20%20%20%20%20context.request.url.toString%28%29.includes%28%22/link-social%22%29%29%20%26%26%0A%20%20%20%20%21context.request%3F.body.includes%28%22idToken%22%29%0A%29%0A%60%60%60%0A%0ASince%20you%27re%20getting%20%60%7Bredirect%3A%20true%2C%20url%3A%20%22...%22%7D%60%20back%2C%20the%20interception%20isn%27t%20triggering.%20Could%20you%20log%20what%20%60context.request.url.toString%28%29%60%20resolves%20to%3F%20The%20URL%20string%20check%20uses%20%60includes%28%22/link-social%22%29%60%20%E2%80%94%20if%20the%20actual%20request%20URL%20doesn%27t%20contain%20that%20exact%20string%20%28e.g.%2C%20different%20casing%2C%20different%20path%20structure%29%2C%20the%20interception%20would%20fail.%0A%0AAlso%20verify%3A%0A1.%20%2A%2AWhat%20endpoint%20URL%20is%20actually%20being%20called%3F%2A%2A%20The%20%60linkSocial%28%29%60%20client%20method%20should%20hit%20something%20like%20%60/api/auth/link-social/facebook%60%0A2.%20%2A%2AIs%20the%20request%20body%20including%20%60idToken%60%3F%2A%2A%20That%20would%20bypass%20interception%0A%0AThis%20looks%20like%20either%20the%20URL%20path%20doesn%27t%20match%20the%20expected%20pattern%2C%20or%20there%27s%20something%20in%20the%20request%20causing%20it%20to%20skip%20the%20browser%20opening%20logic.%20If%20you%20can%20share%20the%20full%20%60context.request.url%60%20value%20when%20%60linkSocial%60%20is%20called%2C%20that%20would%20help%20identify%20where%20the%20mismatch%20is.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8407)
Author
Owner

@PierrickViot-Launier commented on GitHub (Mar 5, 2026):

@dosu

  1. [Auth Request URL] https://unidealistic-brantley-unerasable.ngrok-free.dev/api/auth/get-session
  2. [Auth Request Body] {"provider":"facebook","callbackURL":"invi:///auth/callback","scopes":["public_profile","pages_show_list","instagram_basic","business_management"]}
<!-- gh-comment-id:4002610538 --> @PierrickViot-Launier commented on GitHub (Mar 5, 2026): @dosu 1. `[Auth Request URL] https://unidealistic-brantley-unerasable.ngrok-free.dev/api/auth/get-session` 2. `[Auth Request Body] {"provider":"facebook","callbackURL":"invi:///auth/callback","scopes":["public_profile","pages_show_list","instagram_basic","business_management"]}`
Author
Owner

@dosubot[bot] commented on GitHub (Mar 5, 2026):

Found it! The request URL is /api/auth/get-session, not /api/auth/link-social/facebook.

The redirect interception checks for /link-social in the URL:

context.request.url.toString().includes("/link-social")

But your request is hitting /get-session instead. This explains why the browser never opens — the URL pattern simply doesn't match.

It looks like authClient.linkSocial() is calling the wrong endpoint. Can you confirm:

  1. How are you calling linkSocial? (e.g., authClient.linkSocial({ provider: 'facebook', ... }))
  2. What version of @better-auth/expo are you using? (npm list @better-auth/expo)

This might be a routing issue in how the client method maps to the server endpoint, or possibly the request is being intercepted by session refresh logic before reaching the actual link-social call.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:4002612702 --> @dosubot[bot] commented on GitHub (Mar 5, 2026): <!-- Answer --> Found it! The request URL is `/api/auth/get-session`, **not** `/api/auth/link-social/facebook`. The [redirect interception checks for `/link-social` in the URL](https://github.com/better-auth/better-auth/blob/c15f6d9c0addd4218077f38c13be51cc17b69b42/packages/expo/src/client.ts#L350-L355): ```typescript context.request.url.toString().includes("/link-social") ``` But your request is hitting `/get-session` instead. This explains why the browser never opens — the URL pattern simply doesn't match. It looks like `authClient.linkSocial()` is calling the wrong endpoint. Can you confirm: 1. How are you calling `linkSocial`? (e.g., `authClient.linkSocial({ provider: 'facebook', ... })`) 2. What version of `@better-auth/expo` are you using? (`npm list @better-auth/expo`) This might be a routing issue in how the client method maps to the server endpoint, or possibly the request is being intercepted by session refresh logic before reaching the actual link-social call. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/8478ca0f-1544-4b21-9721-213ae439401b?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/8478ca0f-1544-4b21-9721-213ae439401b?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/8478ca0f-1544-4b21-9721-213ae439401b?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/8478ca0f-1544-4b21-9721-213ae439401b?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/8478ca0f-1544-4b21-9721-213ae439401b?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/8478ca0f-1544-4b21-9721-213ae439401b?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/8478ca0f-1544-4b21-9721-213ae439401b?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Found%20it%21%20The%20request%20URL%20is%20%60/api/auth/get-session%60%2C%20%2A%2Anot%2A%2A%20%60/api/auth/link-social/facebook%60.%20%0A%0AThe%20%5Bredirect%20interception%20checks%20for%20%60/link-social%60%20in%20the%20URL%5D%28https%3A//github.com/better-auth/better-auth/blob/c15f6d9c0addd4218077f38c13be51cc17b69b42/packages/expo/src/client.ts%23L350-L355%29%3A%0A%0A%60%60%60typescript%0Acontext.request.url.toString%28%29.includes%28%22/link-social%22%29%0A%60%60%60%0A%0ABut%20your%20request%20is%20hitting%20%60/get-session%60%20instead.%20This%20explains%20why%20the%20browser%20never%20opens%20%E2%80%94%20the%20URL%20pattern%20simply%20doesn%27t%20match.%0A%0AIt%20looks%20like%20%60authClient.linkSocial%28%29%60%20is%20calling%20the%20wrong%20endpoint.%20Can%20you%20confirm%3A%0A1.%20How%20are%20you%20calling%20%60linkSocial%60%3F%20%28e.g.%2C%20%60authClient.linkSocial%28%7B%20provider%3A%20%27facebook%27%2C%20...%20%7D%29%60%29%0A2.%20What%20version%20of%20%60%40better-auth/expo%60%20are%20you%20using%3F%20%28%60npm%20list%20%40better-auth/expo%60%29%0A%0AThis%20might%20be%20a%20routing%20issue%20in%20how%20the%20client%20method%20maps%20to%20the%20server%20endpoint%2C%20or%20possibly%20the%20request%20is%20being%20intercepted%20by%20session%20refresh%20logic%20before%20reaching%20the%20actual%20link-social%20call.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8407)
Author
Owner

@PierrickViot-Launier commented on GitHub (Mar 5, 2026):

@dosu

My bad, I pasted the wrong console.log

It was this one:

[Auth Request URL] https://unidealistic-brantley-unerasable.ngrok-free.dev/api/auth/link-social

<!-- gh-comment-id:4002629128 --> @PierrickViot-Launier commented on GitHub (Mar 5, 2026): @dosu My bad, I pasted the wrong console.log It was this one: `[Auth Request URL] https://unidealistic-brantley-unerasable.ngrok-free.dev/api/auth/link-social`
Author
Owner

@dosubot[bot] commented on GitHub (Mar 5, 2026):

The URL /api/auth/link-social should match the includes("/link-social") check. So the URL pattern is correct.

Since you confirmed context.data?.redirect is true and your request body doesn't contain idToken, this is strange — all three conditions should be passing.

Can you add some debug logging right before the condition to verify what's happening?

// In your app, temporarily patch or log:
console.log('URL check:', context.request.url.toString().includes("/link-social")); // should be true
console.log('Redirect check:', context.data?.redirect); // should be true  
console.log('idToken check:', !context.request?.body.includes("idToken")); // should be true

Also, one thing to double-check: is isWeb returning true? The hook returns early if isWeb is true:

if (isWeb) return;

This could happen if Platform.OS is being detected as "web" instead of "android". Can you log Platform.OS to confirm it's returning "android"?

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:4002638044 --> @dosubot[bot] commented on GitHub (Mar 5, 2026): <!-- Answer --> The URL `/api/auth/link-social` should match the [`includes("/link-social")` check](https://github.com/better-auth/better-auth/blob/c15f6d9c0addd4218077f38c13be51cc17b69b42/packages/expo/src/client.ts#L350-L355). So the URL pattern is correct. Since you confirmed `context.data?.redirect` is `true` and your request body doesn't contain `idToken`, this is strange — all three conditions should be passing. Can you add some debug logging right before the condition to verify what's happening? ```typescript // In your app, temporarily patch or log: console.log('URL check:', context.request.url.toString().includes("/link-social")); // should be true console.log('Redirect check:', context.data?.redirect); // should be true console.log('idToken check:', !context.request?.body.includes("idToken")); // should be true ``` Also, one thing to double-check: **is `isWeb` returning `true`?** The hook [returns early if `isWeb` is true](https://github.com/better-auth/better-auth/blob/c15f6d9c0addd4218077f38c13be51cc17b69b42/packages/expo/src/client.ts#L319): ```typescript if (isWeb) return; ``` This could happen if `Platform.OS` is being detected as `"web"` instead of `"android"`. Can you log `Platform.OS` to confirm it's returning `"android"`? <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/9980d19f-680a-4674-b725-57bc453927c7?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/9980d19f-680a-4674-b725-57bc453927c7?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/9980d19f-680a-4674-b725-57bc453927c7?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/9980d19f-680a-4674-b725-57bc453927c7?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/9980d19f-680a-4674-b725-57bc453927c7?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/9980d19f-680a-4674-b725-57bc453927c7?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/9980d19f-680a-4674-b725-57bc453927c7?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=The%20URL%20%60/api/auth/link-social%60%20should%20match%20the%20%5B%60includes%28%22/link-social%22%29%60%20check%5D%28https%3A//github.com/better-auth/better-auth/blob/c15f6d9c0addd4218077f38c13be51cc17b69b42/packages/expo/src/client.ts%23L350-L355%29.%20So%20the%20URL%20pattern%20is%20correct.%0A%0ASince%20you%20confirmed%20%60context.data%3F.redirect%60%20is%20%60true%60%20and%20your%20request%20body%20doesn%27t%20contain%20%60idToken%60%2C%20this%20is%20strange%20%E2%80%94%20all%20three%20conditions%20should%20be%20passing.%0A%0ACan%20you%20add%20some%20debug%20logging%20right%20before%20the%20condition%20to%20verify%20what%27s%20happening%3F%0A%0A%60%60%60typescript%0A//%20In%20your%20app%2C%20temporarily%20patch%20or%20log%3A%0Aconsole.log%28%27URL%20check%3A%27%2C%20context.request.url.toString%28%29.includes%28%22/link-social%22%29%29%3B%20//%20should%20be%20true%0Aconsole.log%28%27Redirect%20check%3A%27%2C%20context.data%3F.redirect%29%3B%20//%20should%20be%20true%20%20%0Aconsole.log%28%27idToken%20check%3A%27%2C%20%21context.request%3F.body.includes%28%22idToken%22%29%29%3B%20//%20should%20be%20true%0A%60%60%60%0A%0AAlso%2C%20one%20thing%20to%20double-check%3A%20%2A%2Ais%20%60isWeb%60%20returning%20%60true%60%3F%2A%2A%20The%20hook%20%5Breturns%20early%20if%20%60isWeb%60%20is%20true%5D%28https%3A//github.com/better-auth/better-auth/blob/c15f6d9c0addd4218077f38c13be51cc17b69b42/packages/expo/src/client.ts%23L319%29%3A%0A%0A%60%60%60typescript%0Aif%20%28isWeb%29%20return%3B%0A%60%60%60%0A%0AThis%20could%20happen%20if%20%60Platform.OS%60%20is%20being%20detected%20as%20%60%22web%22%60%20instead%20of%20%60%22android%22%60.%20Can%20you%20log%20%60Platform.OS%60%20to%20confirm%20it%27s%20returning%20%60%22android%22%60%3F)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8407)
Author
Owner

@PierrickViot-Launier commented on GitHub (Mar 5, 2026):

@dosu

export const authClient = createAuthClient({
    baseURL: API_URL,
    plugins: [
        expoClient({
            scheme: 'invi',
            storagePrefix: 'invi',
            storage: SecureStore,
        }),
        inferAdditionalFields({
            user: {
                role: { type: 'string', input: true },
                instagramProfileId: { type: 'number', required: false, input: false },
                deviceTokens: { type: 'string[]', input: false },
            },
        }),
    ],
    // Temporary — add to authClient.ts
    fetchOptions: {
        onRequest: (context) => {
            console.log('[URL check]', context.url.toString().includes('/link-social'));
            console.log('[Redirect check]', context.redirect);
            console.log('[idToken check]', !context.body.includes('idToken'));
        },
    },
});

[Platform] android
[URL check] true
[Redirect check] undefined
[idToken check] true

<!-- gh-comment-id:4002678918 --> @PierrickViot-Launier commented on GitHub (Mar 5, 2026): @dosu ``` export const authClient = createAuthClient({ baseURL: API_URL, plugins: [ expoClient({ scheme: 'invi', storagePrefix: 'invi', storage: SecureStore, }), inferAdditionalFields({ user: { role: { type: 'string', input: true }, instagramProfileId: { type: 'number', required: false, input: false }, deviceTokens: { type: 'string[]', input: false }, }, }), ], // Temporary — add to authClient.ts fetchOptions: { onRequest: (context) => { console.log('[URL check]', context.url.toString().includes('/link-social')); console.log('[Redirect check]', context.redirect); console.log('[idToken check]', !context.body.includes('idToken')); }, }, }); ``` `[Platform] android` `[URL check] true` `[Redirect check] undefined` `[idToken check] true`
Author
Owner

@dosubot[bot] commented on GitHub (Mar 5, 2026):

That's the issue! You're logging in onRequest, but the redirect check needs to happen in onSuccess (after the response comes back). The context.data?.redirect property is only available in the response, not the request.

Your onRequest log shows context.redirect is undefined because the request hasn't been sent yet — there's no response data at that point.

The redirect interception happens in onSuccess where context.data?.redirect should be true from the server response. But earlier you said the response was:

{"data": {"redirect": true, "url": "https://www.facebook.com/..."}, "error": null}

This means the server IS returning redirect: true. The question is why the Expo plugin's onSuccess hook isn't seeing it or isn't triggering the browser.

Can you add an onSuccess hook to your fetchOptions to see what's happening there?

fetchOptions: {
    onSuccess: (context) => {
        console.log('[onSuccess] URL:', context.request.url.toString());
        console.log('[onSuccess] data?.redirect:', context.data?.redirect);
        console.log('[onSuccess] data:', JSON.stringify(context.data));
    },
}

This will help confirm whether the Expo plugin's onSuccess is running before/after your custom one, and whether context.data contains what we expect.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:4002682003 --> @dosubot[bot] commented on GitHub (Mar 5, 2026): <!-- Answer --> That's the issue! You're logging in `onRequest`, but the redirect check needs to happen in **`onSuccess`** (after the response comes back). The `context.data?.redirect` property is only available in the response, not the request. Your `onRequest` log shows `context.redirect` is `undefined` because the request hasn't been sent yet — there's no response data at that point. The [redirect interception happens in `onSuccess`](https://github.com/better-auth/better-auth/blob/c15f6d9c0addd4218077f38c13be51cc17b69b42/packages/expo/src/client.ts#L350-L355) where `context.data?.redirect` should be `true` from the server response. But earlier you said the response was: ```json {"data": {"redirect": true, "url": "https://www.facebook.com/..."}, "error": null} ``` This means the server IS returning `redirect: true`. The question is why the Expo plugin's `onSuccess` hook isn't seeing it or isn't triggering the browser. Can you add an `onSuccess` hook to your fetchOptions to see what's happening there? ```typescript fetchOptions: { onSuccess: (context) => { console.log('[onSuccess] URL:', context.request.url.toString()); console.log('[onSuccess] data?.redirect:', context.data?.redirect); console.log('[onSuccess] data:', JSON.stringify(context.data)); }, } ``` This will help confirm whether the Expo plugin's `onSuccess` is running before/after your custom one, and whether `context.data` contains what we expect. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/6cb61b77-47ef-4a3d-835f-f373c1e8a426?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/6cb61b77-47ef-4a3d-835f-f373c1e8a426?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/6cb61b77-47ef-4a3d-835f-f373c1e8a426?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/6cb61b77-47ef-4a3d-835f-f373c1e8a426?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/6cb61b77-47ef-4a3d-835f-f373c1e8a426?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/6cb61b77-47ef-4a3d-835f-f373c1e8a426?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/6cb61b77-47ef-4a3d-835f-f373c1e8a426?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=That%27s%20the%20issue%21%20You%27re%20logging%20in%20%60onRequest%60%2C%20but%20the%20redirect%20check%20needs%20to%20happen%20in%20%2A%2A%60onSuccess%60%2A%2A%20%28after%20the%20response%20comes%20back%29.%20The%20%60context.data%3F.redirect%60%20property%20is%20only%20available%20in%20the%20response%2C%20not%20the%20request.%0A%0AYour%20%60onRequest%60%20log%20shows%20%60context.redirect%60%20is%20%60undefined%60%20because%20the%20request%20hasn%27t%20been%20sent%20yet%20%E2%80%94%20there%27s%20no%20response%20data%20at%20that%20point.%0A%0AThe%20%5Bredirect%20interception%20happens%20in%20%60onSuccess%60%5D%28https%3A//github.com/better-auth/better-auth/blob/c15f6d9c0addd4218077f38c13be51cc17b69b42/packages/expo/src/client.ts%23L350-L355%29%20where%20%60context.data%3F.redirect%60%20should%20be%20%60true%60%20from%20the%20server%20response.%20But%20earlier%20you%20said%20the%20response%20was%3A%0A%0A%60%60%60json%0A%7B%22data%22%3A%20%7B%22redirect%22%3A%20true%2C%20%22url%22%3A%20%22https%3A//www.facebook.com/...%22%7D%2C%20%22error%22%3A%20null%7D%0A%60%60%60%0A%0AThis%20means%20the%20server%20IS%20returning%20%60redirect%3A%20true%60.%20The%20question%20is%20why%20the%20Expo%20plugin%27s%20%60onSuccess%60%20hook%20isn%27t%20seeing%20it%20or%20isn%27t%20triggering%20the%20browser.%0A%0ACan%20you%20add%20an%20%60onSuccess%60%20hook%20to%20your%20fetchOptions%20to%20see%20what%27s%20happening%20there%3F%0A%0A%60%60%60typescript%0AfetchOptions%3A%20%7B%0A%20%20%20%20onSuccess%3A%20%28context%29%20%3D%3E%20%7B%0A%20%20%20%20%20%20%20%20console.log%28%27%5BonSuccess%5D%20URL%3A%27%2C%20context.request.url.toString%28%29%29%3B%0A%20%20%20%20%20%20%20%20console.log%28%27%5BonSuccess%5D%20data%3F.redirect%3A%27%2C%20context.data%3F.redirect%29%3B%0A%20%20%20%20%20%20%20%20console.log%28%27%5BonSuccess%5D%20data%3A%27%2C%20JSON.stringify%28context.data%29%29%3B%0A%20%20%20%20%7D%2C%0A%7D%0A%60%60%60%0A%0AThis%20will%20help%20confirm%20whether%20the%20Expo%20plugin%27s%20%60onSuccess%60%20is%20running%20before/after%20your%20custom%20one%2C%20and%20whether%20%60context.data%60%20contains%20what%20we%20expect.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8407)
Author
Owner

@PierrickViot-Launier commented on GitHub (Mar 5, 2026):

@dosu

[onSuccess] URL: https://unidealistic-brantley-unerasable.ngrok-free.dev/api/auth/link-social
[onSuccess] data?.redirect: true
[onSuccess] data: {"url":"https://www.facebook.com/v24.0/dialog/oauth?response_type=code&client_id=2620685538285420&state=B67IwsndWLrDKLwSylfn1THVQKRljbkZ&scope=email+public_profile+public_profile+pages_show_list+instagram_basic+business_management&redirect_uri=https%3A%2F%2Funidealistic-brantley-unerasable.ngrok-free.dev%2Fapi%2Fauth%2Fcallback%2Ffacebook&config_id=936411832208329","redirect":true}

<!-- gh-comment-id:4002701883 --> @PierrickViot-Launier commented on GitHub (Mar 5, 2026): @dosu `[onSuccess] URL: https://unidealistic-brantley-unerasable.ngrok-free.dev/api/auth/link-social` `[onSuccess] data?.redirect: true` `[onSuccess] data: {"url":"https://www.facebook.com/v24.0/dialog/oauth?response_type=code&client_id=2620685538285420&state=B67IwsndWLrDKLwSylfn1THVQKRljbkZ&scope=email+public_profile+public_profile+pages_show_list+instagram_basic+business_management&redirect_uri=https%3A%2F%2Funidealistic-brantley-unerasable.ngrok-free.dev%2Fapi%2Fauth%2Fcallback%2Ffacebook&config_id=936411832208329","redirect":true}`
Author
Owner

@dosubot[bot] commented on GitHub (Mar 5, 2026):

This confirms all the conditions are met (data?.redirect: true, URL contains /link-social). The Expo plugin's onSuccess should be triggering the browser.

Your custom onSuccess runs before the Expo plugin's onSuccess, so it shouldn't block it — but let's verify the Expo plugin's hook is actually executing.

Can you add a log inside node_modules to confirm? In node_modules/@better-auth/expo/dist/client.js, find the onSuccess function and add a console.log right before the redirect check:

// Look for something like:
if (context.data?.redirect && ...
// Add before it:
console.log('[Expo Plugin] onSuccess running, redirect:', context.data?.redirect);

Alternatively, if you don't want to patch node_modules, try removing your custom onSuccess temporarily to see if the Expo plugin works on its own:

// Comment out fetchOptions temporarily
// fetchOptions: { ... }

If the browser opens when you remove your custom onSuccess, there might be something in the execution chain causing an issue. If it still doesn't work, we'll know the issue is definitely within the Expo plugin's logic itself.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:4002711277 --> @dosubot[bot] commented on GitHub (Mar 5, 2026): <!-- Answer --> This confirms all the conditions are met (`data?.redirect: true`, URL contains `/link-social`). The Expo plugin's `onSuccess` should be triggering the browser. Your custom `onSuccess` runs **before** the [Expo plugin's `onSuccess`](https://github.com/better-auth/better-auth/blob/c15f6d9c0addd4218077f38c13be51cc17b69b42/packages/expo/src/client.ts#L318-L408), so it shouldn't block it — but let's verify the Expo plugin's hook is actually executing. Can you add a log inside node_modules to confirm? In `node_modules/@better-auth/expo/dist/client.js`, find the `onSuccess` function and add a console.log right before the redirect check: ```javascript // Look for something like: if (context.data?.redirect && ... // Add before it: console.log('[Expo Plugin] onSuccess running, redirect:', context.data?.redirect); ``` Alternatively, if you don't want to patch node_modules, try removing your custom `onSuccess` temporarily to see if the Expo plugin works on its own: ```typescript // Comment out fetchOptions temporarily // fetchOptions: { ... } ``` If the browser opens when you remove your custom `onSuccess`, there might be something in the execution chain causing an issue. If it still doesn't work, we'll know the issue is definitely within the Expo plugin's logic itself. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/f70786a8-02a2-4d05-afdd-53cce16883a3?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/f70786a8-02a2-4d05-afdd-53cce16883a3?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/f70786a8-02a2-4d05-afdd-53cce16883a3?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/f70786a8-02a2-4d05-afdd-53cce16883a3?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/f70786a8-02a2-4d05-afdd-53cce16883a3?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/f70786a8-02a2-4d05-afdd-53cce16883a3?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/f70786a8-02a2-4d05-afdd-53cce16883a3?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=This%20confirms%20all%20the%20conditions%20are%20met%20%28%60data%3F.redirect%3A%20true%60%2C%20URL%20contains%20%60/link-social%60%29.%20The%20Expo%20plugin%27s%20%60onSuccess%60%20should%20be%20triggering%20the%20browser.%0A%0AYour%20custom%20%60onSuccess%60%20runs%20%2A%2Abefore%2A%2A%20the%20%5BExpo%20plugin%27s%20%60onSuccess%60%5D%28https%3A//github.com/better-auth/better-auth/blob/c15f6d9c0addd4218077f38c13be51cc17b69b42/packages/expo/src/client.ts%23L318-L408%29%2C%20so%20it%20shouldn%27t%20block%20it%20%E2%80%94%20but%20let%27s%20verify%20the%20Expo%20plugin%27s%20hook%20is%20actually%20executing.%0A%0ACan%20you%20add%20a%20log%20inside%20node_modules%20to%20confirm%3F%20In%20%60node_modules/%40better-auth/expo/dist/client.js%60%2C%20find%20the%20%60onSuccess%60%20function%20and%20add%20a%20console.log%20right%20before%20the%20redirect%20check%3A%0A%0A%60%60%60javascript%0A//%20Look%20for%20something%20like%3A%0Aif%20%28context.data%3F.redirect%20%26%26%20...%0A//%20Add%20before%20it%3A%0Aconsole.log%28%27%5BExpo%20Plugin%5D%20onSuccess%20running%2C%20redirect%3A%27%2C%20context.data%3F.redirect%29%3B%0A%60%60%60%0A%0AAlternatively%2C%20if%20you%20don%27t%20want%20to%20patch%20node_modules%2C%20try%20removing%20your%20custom%20%60onSuccess%60%20temporarily%20to%20see%20if%20the%20Expo%20plugin%20works%20on%20its%20own%3A%0A%0A%60%60%60typescript%0A//%20Comment%20out%20fetchOptions%20temporarily%0A//%20fetchOptions%3A%20%7B%20...%20%7D%0A%60%60%60%0A%0AIf%20the%20browser%20opens%20when%20you%20remove%20your%20custom%20%60onSuccess%60%2C%20there%20might%20be%20something%20in%20the%20execution%20chain%20causing%20an%20issue.%20If%20it%20still%20doesn%27t%20work%2C%20we%27ll%20know%20the%20issue%20is%20definitely%20within%20the%20Expo%20plugin%27s%20logic%20itself.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8407)
Author
Owner

@PierrickViot-Launier commented on GitHub (Mar 5, 2026):

@dosu

Update: I tested on a dummy app and everything works flawlessly.

The issue must be on my end in my config and / or navigation setup

<!-- gh-comment-id:4005706491 --> @PierrickViot-Launier commented on GitHub (Mar 5, 2026): @dosu Update: I tested on a dummy app and everything works flawlessly. The issue must be on my end in my config and / or navigation setup
Author
Owner

@dosubot[bot] commented on GitHub (Mar 5, 2026):

Good to hear you narrowed it down! Since it works in a fresh app, the issue is likely in how your main app's configuration interacts with the Expo plugin. A few things to check:

  1. Plugin order — If you have other client plugins that also define onSuccess hooks, they might be interfering. Try moving expoClient() to the first position in your plugins array.

  2. Custom fetch interceptors — Any global fetch interceptors, Axios instances, or request/response wrappers could be modifying the response before the Expo plugin sees it.

  3. Navigation deep link handlers — If React Navigation is aggressively intercepting deep links, it might be catching the callback before the Expo plugin can process it. Check if you have any custom linking config or deep link listeners that could conflict.

  4. Multiple auth client instances — Make sure you don't have multiple createAuthClient() calls that might be causing race conditions.

Feel free to close this issue if you've resolved it, or share your config differences between the working dummy app and your main app if you'd like help pinpointing the exact cause!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:4005713030 --> @dosubot[bot] commented on GitHub (Mar 5, 2026): <!-- Answer --> Good to hear you narrowed it down! Since it works in a fresh app, the issue is likely in how your main app's configuration interacts with the Expo plugin. A few things to check: 1. **Plugin order** — If you have other client plugins that also define `onSuccess` hooks, they might be interfering. Try moving `expoClient()` to the first position in your plugins array. 2. **Custom fetch interceptors** — Any global fetch interceptors, Axios instances, or request/response wrappers could be modifying the response before the Expo plugin sees it. 3. **Navigation deep link handlers** — If React Navigation is aggressively intercepting deep links, it might be catching the callback before the Expo plugin can process it. Check if you have any custom `linking` config or deep link listeners that could conflict. 4. **Multiple auth client instances** — Make sure you don't have multiple `createAuthClient()` calls that might be causing race conditions. Feel free to close this issue if you've resolved it, or share your config differences between the working dummy app and your main app if you'd like help pinpointing the exact cause! <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/37b47cb3-4ffd-4865-b9f4-868a752ae69b?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/37b47cb3-4ffd-4865-b9f4-868a752ae69b?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/37b47cb3-4ffd-4865-b9f4-868a752ae69b?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/37b47cb3-4ffd-4865-b9f4-868a752ae69b?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/37b47cb3-4ffd-4865-b9f4-868a752ae69b?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/37b47cb3-4ffd-4865-b9f4-868a752ae69b?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/37b47cb3-4ffd-4865-b9f4-868a752ae69b?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Good%20to%20hear%20you%20narrowed%20it%20down%21%20Since%20it%20works%20in%20a%20fresh%20app%2C%20the%20issue%20is%20likely%20in%20how%20your%20main%20app%27s%20configuration%20interacts%20with%20the%20Expo%20plugin.%20A%20few%20things%20to%20check%3A%0A%0A1.%20%2A%2APlugin%20order%2A%2A%20%E2%80%94%20If%20you%20have%20other%20client%20plugins%20that%20also%20define%20%60onSuccess%60%20hooks%2C%20they%20might%20be%20interfering.%20Try%20moving%20%60expoClient%28%29%60%20to%20the%20first%20position%20in%20your%20plugins%20array.%0A%0A2.%20%2A%2ACustom%20fetch%20interceptors%2A%2A%20%E2%80%94%20Any%20global%20fetch%20interceptors%2C%20Axios%20instances%2C%20or%20request/response%20wrappers%20could%20be%20modifying%20the%20response%20before%20the%20Expo%20plugin%20sees%20it.%0A%0A3.%20%2A%2ANavigation%20deep%20link%20handlers%2A%2A%20%E2%80%94%20If%20React%20Navigation%20is%20aggressively%20intercepting%20deep%20links%2C%20it%20might%20be%20catching%20the%20callback%20before%20the%20Expo%20plugin%20can%20process%20it.%20Check%20if%20you%20have%20any%20custom%20%60linking%60%20config%20or%20deep%20link%20listeners%20that%20could%20conflict.%0A%0A4.%20%2A%2AMultiple%20auth%20client%20instances%2A%2A%20%E2%80%94%20Make%20sure%20you%20don%27t%20have%20multiple%20%60createAuthClient%28%29%60%20calls%20that%20might%20be%20causing%20race%20conditions.%0A%0AFeel%20free%20to%20close%20this%20issue%20if%20you%27ve%20resolved%20it%2C%20or%20share%20your%20config%20differences%20between%20the%20working%20dummy%20app%20and%20your%20main%20app%20if%20you%27d%20like%20help%20pinpointing%20the%20exact%20cause%21)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8407)
Author
Owner

@PierrickViot-Launier commented on GitHub (Mar 5, 2026):

@dosu

Found the root cause — it was NOT a Better Auth or Expo plugin issue.

The crash was caused by expo-notifications' addNotificationResponseReceivedListener firing spuriously when Chrome returns to the app on Android. Android treats Chrome's referrer intent as a notification response, which triggered navigation to our Chat screen with no params → crash.

The notification response data contained Chrome metadata instead of push notification data:

{
  "android.intent.extra.REFERRER": "https://m.facebook.com/dialog/oauth/...",
  "com.android.browser.application_id": "com.android.chrome",
  "org.chromium.chrome.browser.referrer_id": 12
}

Fix: Added a guard in the notification response listener to validate required data before navigating:

responseListener.current = Notifications.addNotificationResponseReceivedListener(
    (response) => {
        const data = response.notification.request.content.data;

        if (!data.roomId || !data.claim || !data.receiverId) {
            return;
        }

        // Navigate to Chat only with valid notification data
        linkTo('Chat', { roomId: data.roomId, claim: data.claim, receiverId: data.receiverId });
    },
);

This is a defensive programming fix that should exist regardless — any malformed notification or spurious Android intent would have caused the same crash. The linkSocial and signIn.social flows both work correctly. Thanks for the help debugging!

<!-- gh-comment-id:4006328029 --> @PierrickViot-Launier commented on GitHub (Mar 5, 2026): @dosu Found the root cause — it was NOT a Better Auth or Expo plugin issue. The crash was caused by expo-notifications' addNotificationResponseReceivedListener firing spuriously when Chrome returns to the app on Android. Android treats Chrome's referrer intent as a notification response, which triggered navigation to our Chat screen with no params → crash. The notification response data contained Chrome metadata instead of push notification data: ``` { "android.intent.extra.REFERRER": "https://m.facebook.com/dialog/oauth/...", "com.android.browser.application_id": "com.android.chrome", "org.chromium.chrome.browser.referrer_id": 12 } ``` Fix: Added a guard in the notification response listener to validate required data before navigating: ``` responseListener.current = Notifications.addNotificationResponseReceivedListener( (response) => { const data = response.notification.request.content.data; if (!data.roomId || !data.claim || !data.receiverId) { return; } // Navigate to Chat only with valid notification data linkTo('Chat', { roomId: data.roomId, claim: data.claim, receiverId: data.receiverId }); }, ); ``` This is a defensive programming fix that should exist regardless — any malformed notification or spurious Android intent would have caused the same crash. The linkSocial and signIn.social flows both work correctly. Thanks for the help debugging!
Author
Owner

@dosubot[bot] commented on GitHub (Mar 5, 2026):

Great detective work! That's a tricky edge case — Android interpreting Chrome's referrer intent as a notification response is definitely unexpected behavior. Your guard fix is the right approach and will protect against any future spurious intents.

Thanks for sharing the root cause and solution — this will be helpful for anyone else who encounters similar crashes when combining expo-notifications with OAuth flows on Android. Glad the auth flows are working correctly!

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

<!-- gh-comment-id:4006329666 --> @dosubot[bot] commented on GitHub (Mar 5, 2026): <!-- Answer --> Great detective work! That's a tricky edge case — Android interpreting Chrome's referrer intent as a notification response is definitely unexpected behavior. Your guard fix is the right approach and will protect against any future spurious intents. Thanks for sharing the root cause and solution — this will be helpful for anyone else who encounters similar crashes when combining `expo-notifications` with OAuth flows on Android. Glad the auth flows are working correctly! <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/bcbf839f-05e6-4c9e-b058-7150fee943dc?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/bcbf839f-05e6-4c9e-b058-7150fee943dc?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/bcbf839f-05e6-4c9e-b058-7150fee943dc?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/bcbf839f-05e6-4c9e-b058-7150fee943dc?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/bcbf839f-05e6-4c9e-b058-7150fee943dc?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/bcbf839f-05e6-4c9e-b058-7150fee943dc?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/bcbf839f-05e6-4c9e-b058-7150fee943dc?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Great%20detective%20work%21%20That%27s%20a%20tricky%20edge%20case%20%E2%80%94%20Android%20interpreting%20Chrome%27s%20referrer%20intent%20as%20a%20notification%20response%20is%20definitely%20unexpected%20behavior.%20Your%20guard%20fix%20is%20the%20right%20approach%20and%20will%20protect%20against%20any%20future%20spurious%20intents.%0A%0AThanks%20for%20sharing%20the%20root%20cause%20and%20solution%20%E2%80%94%20this%20will%20be%20helpful%20for%20anyone%20else%20who%20encounters%20similar%20crashes%20when%20combining%20%60expo-notifications%60%20with%20OAuth%20flows%20on%20Android.%20Glad%20the%20auth%20flows%20are%20working%20correctly%21)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/8407)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#28402