diff --git a/.changeset/expo-link-social-id-token.md b/.changeset/expo-link-social-id-token.md new file mode 100644 index 0000000000..b867240cac --- /dev/null +++ b/.changeset/expo-link-social-id-token.md @@ -0,0 +1,5 @@ +--- +"@better-auth/expo": patch +--- + +Include the stored session cookie when linking a social account with an ID token in Expo apps. diff --git a/packages/expo/src/client.ts b/packages/expo/src/client.ts index f49f42c1a2..796685aa6f 100644 --- a/packages/expo/src/client.ts +++ b/packages/expo/src/client.ts @@ -534,8 +534,12 @@ export const expoClient = (opts: ExpoClientOptions) => { const isIdTokenRequest = options.body?.idToken !== undefined; if (isIdTokenRequest) { + const cookie = url.includes("/link-social") + ? getCookie(storage.getItem(cookieName) || "{}") + : ""; options.headers = { ...options.headers, + ...(cookie ? { cookie } : {}), "x-skip-oauth-proxy": "true", }; } else { diff --git a/packages/expo/test/expo.test.ts b/packages/expo/test/expo.test.ts index dd556c5518..f5c9971b95 100644 --- a/packages/expo/test/expo.test.ts +++ b/packages/expo/test/expo.test.ts @@ -578,6 +578,65 @@ describe("expo", async () => { expect(originHeader).toBeNull(); }); + /** + * @see https://github.com/better-auth/better-auth/issues/9900 + */ + it("should send cookie for link-social ID token requests", async () => { + let cookieHeader: string | null | undefined = null; + let expoOriginHeader: string | null | undefined = null; + const storage = new Map(); + + storage.set( + "better-auth_cookie", + JSON.stringify({ + "better-auth.session_token": { + value: "existing-token", + expires: new Date(Date.now() + 1000 * 60 * 60).toISOString(), + }, + }), + ); + + const { client } = await getTestInstance( + { + hooks: { + before: createAuthMiddleware(async (ctx) => { + cookieHeader = ctx.request?.headers.get("cookie"); + expoOriginHeader = ctx.request?.headers.get("expo-origin"); + }), + }, + socialProviders: { + google: { + clientId: "test", + clientSecret: "test", + }, + }, + plugins: [expo()], + }, + { + clientOptions: { + plugins: [ + expoClient({ + storage: { + getItem: (key) => storage.get(key) || null, + setItem: async (key, value) => storage.set(key, value), + }, + }), + ], + }, + }, + ); + + await client.linkSocial({ + provider: "google", + idToken: { + token: "fake-id-token", + }, + }); + + expect(cookieHeader).toContain("better-auth.session_token=existing-token"); + expect(expoOriginHeader).toBeNull(); + }); + it("should preserve existing cookies on link-social", async () => { await client.signIn.email({ email: testUser.email,