# Social Login and Account Linking — Authentication & Authorization

Source: https://www.skillbyai.com/en/authentication/m-social

> Federated sign-in without account takeover.

## Pitfalls of signing in with another provider

Social login ("Sign in with Google/Apple/GitHub") uses OIDC or OAuth to delegate authentication. The main risk is **account linking**: if a provider asserts `alice@example.com` and you automatically attach it to an existing local account with that email, an attacker who controls an unverified email at some provider can take over the account. Rules: key external identities by (`iss`, `sub`); only trust the email when the provider marks it verified **and** you trust that provider to vouch for that domain; for linking to an existing account, require the user to **sign in to the existing account first** (or prove control by another method) before adding the new identity. Also handle users losing access to the provider, and let them add a second login method.

## Safe linking logic

Pseudocode for handling a callback from an external provider.

```typescript
async function onExternalLogin(claims: { iss: string; sub: string; email?: string; email_verified?: boolean },
                               currentUser: User | null) {
  // 1. Known external identity => log in that user
  const linked = await db.identities.find(claims.iss, claims.sub);
  if (linked) return login(linked.userId);

  // 2. User is already signed in and chose 'connect account' => link explicitly
  if (currentUser) {
    await db.identities.insert({ userId: currentUser.id, iss: claims.iss, sub: claims.sub });
    return login(currentUser.id);
  }

  // 3. Email matches an existing account => do NOT auto-link
  if (claims.email && (await db.users.findByEmail(claims.email))) {
    return promptSignInToExistingAccountThenLink(claims);
  }

  // 4. Brand new user
  const user = await db.users.create({ email: claims.email_verified ? claims.email : undefined });
  await db.identities.insert({ userId: user.id, iss: claims.iss, sub: claims.sub });
  return login(user.id);
}
```

## Plan for provider changes

Users lose access to social accounts and providers change policies. Encourage a second sign-in method, and keep the external identity in its own table so one user can have several.

**Quiz:** What is the safest way to link a new social identity to an existing account with the same email?

- [x] Require the user to sign in to the existing account first, then link
- [ ] Link automatically whenever emails match
- [ ] Create a duplicate account silently
- [ ] Ask the provider for the user's password

*Answer:* Require the user to sign in to the existing account first, then link. Matching emails alone can be spoofed or unverified.
