[PR #8983] [MERGED] fix(oauth2): prevent cross-provider account collision in link-social callback #16593

Closed
opened 2026-04-13 10:35:55 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/8983
Author: @jaydeep-pipaliya
Created: 4/6/2026
Status: Merged
Merged: 4/9/2026
Merged by: @gustavovalverde

Base: mainHead: fix/link-social-provider-scoped-account-lookup


📝 Commits (2)

  • 9bd7af6 fix(oauth2): use provider-scoped account lookup in link-social callback
  • 9c9fb5b chore: add changeset for provider-scoped link-social fix

📊 Changes

3 files changed (+190 additions, -3 deletions)

View changed files

.changeset/fix-link-social-provider-scope.md (+9 -0)
📝 packages/better-auth/src/api/routes/callback.ts (+5 -3)
📝 packages/better-auth/src/oauth2/link-account.test.ts (+176 -0)

📄 Description

Summary

Fixes #8906

The link-social callback at packages/better-auth/src/api/routes/callback.ts:196 used findAccount(String(userInfo.id)) which searches by accountId across all providers. When two different providers return the same numeric user ID (e.g. both GitHub and Google happen to return id = 99999), the lookup could match an account belonging to a completely different provider and a different user, causing a spurious account_already_linked_to_different_user error or — worse — silently updating the wrong account's tokens.

The generic OAuth plugin already does this correctly using findAccountByProviderId. This PR applies the same provider-scoped lookup to the main social callback link path.

Change

- const existingAccount = await c.context.internalAdapter.findAccount(
-     String(userInfo.id),
- );
+ const existingAccount =
+     await c.context.internalAdapter.findAccountByProviderId(
+         String(userInfo.id),
+         provider.id,
+     );

Test

Added a regression test in link-account.test.ts that:

  1. Creates User A with a Google account (accountId = "99999")
  2. Creates User B (email/password) and links GitHub — also returning accountId "99999"
  3. Verifies User B's GitHub link succeeds without error (old code would return account_already_linked_to_different_user)
  4. Verifies User A's Google account is untouched

Summary by cubic

Scopes account lookup by provider in the OAuth2 link-social callback to prevent collisions when different providers return the same account ID. This avoids false account_already_linked_to_different_user errors and accidental token updates.

  • Bug Fixes
    • Use findAccountByProviderId(accountId, provider.id) instead of findAccount(accountId) in the link-social path.
    • Add regression test to ensure linking github does not collide with an existing google account sharing the same numeric ID, and that the original account remains unchanged.
    • Add changeset entry for a patch release.

Written for commit 9c9fb5bbbf. Summary will update on new commits.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/better-auth/better-auth/pull/8983 **Author:** [@jaydeep-pipaliya](https://github.com/jaydeep-pipaliya) **Created:** 4/6/2026 **Status:** ✅ Merged **Merged:** 4/9/2026 **Merged by:** [@gustavovalverde](https://github.com/gustavovalverde) **Base:** `main` ← **Head:** `fix/link-social-provider-scoped-account-lookup` --- ### 📝 Commits (2) - [`9bd7af6`](https://github.com/better-auth/better-auth/commit/9bd7af6eeef379972393d6cb6b9595f749a8f17e) fix(oauth2): use provider-scoped account lookup in link-social callback - [`9c9fb5b`](https://github.com/better-auth/better-auth/commit/9c9fb5bbbf0573d06adfa9f0d37f33be0144e6b3) chore: add changeset for provider-scoped link-social fix ### 📊 Changes **3 files changed** (+190 additions, -3 deletions) <details> <summary>View changed files</summary> ➕ `.changeset/fix-link-social-provider-scope.md` (+9 -0) 📝 `packages/better-auth/src/api/routes/callback.ts` (+5 -3) 📝 `packages/better-auth/src/oauth2/link-account.test.ts` (+176 -0) </details> ### 📄 Description ## Summary Fixes #8906 The `link-social` callback at `packages/better-auth/src/api/routes/callback.ts:196` used `findAccount(String(userInfo.id))` which searches by `accountId` across **all providers**. When two different providers return the same numeric user ID (e.g. both GitHub and Google happen to return `id = 99999`), the lookup could match an account belonging to a completely different provider and a different user, causing a spurious `account_already_linked_to_different_user` error or — worse — silently updating the wrong account's tokens. The generic OAuth plugin already does this correctly using `findAccountByProviderId`. This PR applies the same provider-scoped lookup to the main social callback link path. ## Change ```diff - const existingAccount = await c.context.internalAdapter.findAccount( - String(userInfo.id), - ); + const existingAccount = + await c.context.internalAdapter.findAccountByProviderId( + String(userInfo.id), + provider.id, + ); ``` ## Test Added a regression test in `link-account.test.ts` that: 1. Creates User A with a Google account (accountId = `"99999"`) 2. Creates User B (email/password) and links GitHub — also returning accountId `"99999"` 3. Verifies User B's GitHub link succeeds without error (old code would return `account_already_linked_to_different_user`) 4. Verifies User A's Google account is untouched <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Scopes account lookup by provider in the OAuth2 link-social callback to prevent collisions when different providers return the same account ID. This avoids false `account_already_linked_to_different_user` errors and accidental token updates. - **Bug Fixes** - Use `findAccountByProviderId(accountId, provider.id)` instead of `findAccount(accountId)` in the link-social path. - Add regression test to ensure linking `github` does not collide with an existing `google` account sharing the same numeric ID, and that the original account remains unchanged. - Add changeset entry for a patch release. <sup>Written for commit 9c9fb5bbbf0573d06adfa9f0d37f33be0144e6b3. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-13 10:35:55 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#16593