OAuth 2.0 and Social LoginLesson 4.3
How to link social accounts to existing users
account linking, email matching, multiple providers, googleId vs githubId columns, merging accounts, preventing duplicate accounts, conflict resolution
The Account Linking Problem
When a user authenticates with Google, you get a profile with a Google ID and email. Three scenarios are possible, and you must handle all three.
Scenario Handling
async (accessToken, refreshToken, profile, done) => {
const googleId = profile.id;
const email = profile.emails[0].value;
// 1. Check if a user with this Google ID already exists
let user = await db.findByGoogleId(googleId);
if (user) return done(null, user);
// 2. Check if a user with this email exists (but no Google ID yet)
user = await db.findByEmail(email);
if (user) {
// Link the Google account to the existing user
await db.updateUser(user.id, { googleId });
return done(null, user);
}
// 3. No match — create a new user
user = await db.createUser({ googleId, email, name: profile.displayName });
return done(null, user);
}
Security Note on Email Matching
Only auto-link accounts via email if you trust that the OAuth provider has verified the email. Google marks unverified emails — check profile.emails[0].verified. If the email is not verified, do not auto-link. Instead, prompt the user to log in with their existing credentials first, then explicitly link the accounts. Auto-linking unverified emails can be exploited to take over accounts.
