Symptom
User signs up locally with `brisorgueilp@gmail.com`. Later tries to sign in with Google using the same email. Result: Mongo E11000 duplicate key error on insert → OAuth callback fails → user is stuck.
Root cause
`modules/auth/controllers/auth.controller.js:303` — `checkOAuthUserProfile` looks up only by `(provider, providerData.sub)`. If no match, it falls through to `UserService.create` with the email. `users.model.mongoose.js:20` has `email: { unique: true }` → insert fails.
No account linking logic exists.
Fix
In `checkOAuthUserProfile`:
- Lookup by `(provider, providerData[key])` — current behavior.
- If no match, lookup by `email`.
- If match found AND `emailVerified: true` on the existing user → attach `providerData[key]` to existing user (patch it with `provider` + `providerData`), return it.
- If match found but `emailVerified: false` → reject with a clear error (avoid account takeover of unverified locals).
- If no email match → create as today.
Security rationale
Google and Apple guarantee `email_verified`. So linking to a local user who also verified their email is safe. Linking to an unverified local user would allow takeover: malicious signup with a victim's email (no verif), then victim signs in via Google → takes over the attacker-controlled doc.
Impact
- Affects Google and Apple.
- Critical UX: currently a user who forgot they already have a local account is permanently locked out.
Tests
- Existing local user + verified → Google signin links and returns existing user.
- Existing local user + unverified → Google signin rejected with 422.
- No existing user → Google signin creates new user (current behavior).
Symptom
User signs up locally with `brisorgueilp@gmail.com`. Later tries to sign in with Google using the same email. Result: Mongo E11000 duplicate key error on insert → OAuth callback fails → user is stuck.
Root cause
`modules/auth/controllers/auth.controller.js:303` — `checkOAuthUserProfile` looks up only by `(provider, providerData.sub)`. If no match, it falls through to `UserService.create` with the email. `users.model.mongoose.js:20` has `email: { unique: true }` → insert fails.
No account linking logic exists.
Fix
In `checkOAuthUserProfile`:
Security rationale
Google and Apple guarantee `email_verified`. So linking to a local user who also verified their email is safe. Linking to an unverified local user would allow takeover: malicious signup with a victim's email (no verif), then victim signs in via Google → takes over the attacker-controlled doc.
Impact
Tests