{"record":{"id":"44e3ef1d1ec7e7db","repo":"sahat/hackathon-starter","slug":"provider-collision","errorCode":"PROVIDER_COLLISION","errorMessage":"PROVIDER_COLLISION","messagePattern":"PROVIDER_COLLISION","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"config/passport.js","lineNumber":84,"sourceCode":" *   - Check if it's a returning user.\n *     - If returning user, sign in and we are done.\n *     - Else check if there is an existing account with user's email.\n *       - If there is, return an error message.\n *       - Else create a new account.\n */\n\n/**\n * Helper function that contains the shared post-profile OAuth logic\n * (supports OAuth 1.0a and OAuth 2.0 providers).\n * Returns User (new or updated) on success or throws Error on failure.\n */\nasync function handleAuthLogin(req, accessToken, refreshToken, providerName, params, providerProfile, sessionAlreadyLoggedIn, tokenSecret, oauth2provider, tokenConfig = {}, refreshTokenExpiration = null) {\n  if (sessionAlreadyLoggedIn) {\n    const existingUser = await User.findOne({\n      [providerName]: { $eq: providerProfile.id },\n    });\n    if (existingUser && existingUser.id !== req.user.id) {\n      throw new Error('PROVIDER_COLLISION');\n    }\n    let user;\n    if (oauth2provider) {\n      user = await saveOAuth2UserTokens(req, accessToken, refreshToken, params.expires_in, refreshTokenExpiration, providerName, tokenConfig);\n    } else {\n      user = await User.findById(req.user.id);\n      user.tokens.push({ kind: providerName, accessToken, ...(tokenSecret && { tokenSecret }) });\n    }\n    user[providerName] = providerProfile.id;\n    user.profile.name = user.profile.name || providerProfile.name;\n    user.profile.gender = user.profile.gender || providerProfile.gender;\n\n    if (providerProfile.picture) {\n      if (!user.profile.pictures || user.profile.pictureSource === undefined) {\n        // legacy account (pre-multi-picture support)\n        user.profile.pictures = new Map();\n        user.profile.picture = providerProfile.picture;\n        user.profile.pictureSource = providerName;","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/sahat/hackathon-starter/blob/c12e339564db59443df0b901818c9bb661331b28/config/passport.js#L66-L102","documentation":"Thrown by handleAuthLogin when a logged-in user attempts to link an OAuth provider account that is already linked to a different local user. The code looks up a User whose provider field equals the provider profile id and compares it to req.user.id; a mismatch means the provider identity belongs to someone else.","triggerScenarios":"User A is logged in and visits /auth/<provider> (account-linking flow) while the provider account (e.g. a Google id) is already stored on User B's document; User.findOne({[providerName]: providerProfile.id}) returns B, whose id !== req.user.id.","commonSituations":"Two team members sharing one OAuth account (shared Twitter/Facebook login), a user who previously created a separate account with the same provider identity, or testing account linking while logged in as a different user.","solutions":["Log in with the provider account directly instead of linking it, or link the provider from the account that actually owns it","If the provider identity is stale, unlink it from the other account first via /account/unlink/:provider","Inspect the User collection for duplicate provider ids and consolidate accounts manually (mongodb shell)"],"exampleFix":"// before: logged in as A, trying to link provider owned by B\n// after: check ownership before linking\nconst owner = await User.findOne({ [provider]: profile.id });\nif (owner && owner.id !== req.user.id) {\n  req.flash('errors', { msg: 'That account is already linked to another user.' });\n  return res.redirect('/account');\n}","handlingStrategy":"validation","validationCode":"const owner = await User.findOne({ [provider]: providerProfile.id });\nif (owner && owner.id !== currentUser.id) {\n  // block linking, show explanatory flash message\n}","typeGuard":null,"tryCatchPattern":"catch (e) { if (e.message === 'PROVIDER_COLLISION') { req.flash('errors', {msg:'That account belongs to another user'}); return res.redirect('/account'); } throw e; }","preventionTips":["Show linked-provider ownership on the profile page before linking","Educate users that one provider identity maps to exactly one local account"],"tags":["oauth","account-linking","multi-user","passport"],"backgroundTag":"oauth-account-linking-collision","analyzedSha":"c12e339564db59443df0b901818c9bb661331b28","analyzedAt":"2026-08-27T11:05:00.872Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}