from api/passport.js. connect method
// Scenario: A new user is attempting to sign up using a third-party
// authentication provider.
// Action: Create a new user and assign them a passport.
if (!passport) {
return sails.models.user.create(user)
.then(function (_user) {
user = user;
return sails.models.passport.create(.extend({ user: user.id }, query))
})
.then(function (passport) {
next(null, user);
})
.catch(next);
}
The use case of a user creates a local account. The user comes back in another time and clicks a passport-[external] without an active session and auth (because users do that kind of thing). In this scenario there will be no req.user and no passport and user.create will eventually throw a duplicate key error on username or email if the user used either.
The simple fix is just change that .create to a .findOrCreate and match on emails since the assumption is it's the same person.
A more complicated fix is to mimic other identity providers that account for mixing internal / external auth with a partial login status and an explicit external authentication call back that allows the app to decide how to bind external and local accounts.
sample flow:
user clicks on external auth provider
external auth provider responds with a success (access or identity token)
auth system calls external login callback
[(sample external login callback)
check if external identity is mapped to local account:
yes - set status return full login
no - {
check if user identity exists by identifier:
yes - ask user to provider existing username & password, map accounts return full login
no - ask user to register a local account, map external account return full login
}
]
I had the same issue (using facebook-token, user logs in again from another browser/device, and app attempts to create duplicate user), and the user.create to user.findOrCreate solution solved it.
from api/passport.js. connect method // Scenario: A new user is attempting to sign up using a third-party // authentication provider. // Action: Create a new user and assign them a passport. if (!passport) { return sails.models.user.create(user) .then(function (_user) { user = user; return sails.models.passport.create(.extend({ user: user.id }, query)) }) .then(function (passport) { next(null, user); }) .catch(next); }
The use case of a user creates a local account. The user comes back in another time and clicks a passport-[external] without an active session and auth (because users do that kind of thing). In this scenario there will be no req.user and no passport and user.create will eventually throw a duplicate key error on username or email if the user used either.
The simple fix is just change that .create to a .findOrCreate and match on emails since the assumption is it's the same person.
A more complicated fix is to mimic other identity providers that account for mixing internal / external auth with a partial login status and an explicit external authentication call back that allows the app to decide how to bind external and local accounts.
sample flow:
user clicks on external auth provider external auth provider responds with a success (access or identity token) auth system calls external login callback [(sample external login callback) check if external identity is mapped to local account: yes - set status return full login no - { check if user identity exists by identifier: yes - ask user to provider existing username & password, map accounts return full login no - ask user to register a local account, map external account return full login } ]