Mongoose User model for handling local and social auth providers Mongoose User model for handling local and social auth providers express express

Mongoose User model for handling local and social auth providers


So I found a working solution for myself which might help other people with the same problem. In my User model I have my usual fields and for each social provider I have a separate array like so (users/User.js):

let userSchema = mongoose.Schema({    email: { type: String, unique: true },    name: { type: String },    password: { type: String },    roles: [String],    confirmation_code: String,    confirmed: { type: Boolean, default: false },    facebook: {        id: String,        token: String,        email: String,        name: String    },    google: {        id: String,        token: String,        email: String,        name: String    }}, { timestamps: true });

When authenticating with a social provider I make an extra check if a user with the same email already exists. If it doesn't, I create a new user. If it does I just add the social provider data (id, token, etc.) to the already existing users array like so (config/passport.js):

passport.use(new FacebookStrategy({    clientID: oauth.facebook.clientID,    clientSecret: oauth.facebook.clientSecret,    callbackURL: oauth.facebook.callbackURL,    profileFields: ['id', 'emails', 'name']},    function (accessToken, refreshToken, profile, done) {        process.nextTick(function () {            User.findOne({                $or: [                    { 'facebook.id': profile.id },                    { 'email': profile.emails[0].value }                ]            }, function (err, user) {                if (err) {                    return done(err);                }                if (user) {                    if (user.facebook.id == undefined) {                        user.facebook.id = profile.id;                        user.facebook.token = accessToken;                        user.facebook.email = profile.emails[0].value;                        user.facebook.name = profile.name.givenName + ' ' + profile.name.familyName;                        user.save();                    }                    return done(null, user);                } else {                    let newUser = new User();                    newUser.facebook.id = profile.id;                    newUser.facebook.token = accessToken;                    newUser.facebook.email = profile.emails[0].value;                    newUser.facebook.name = profile.name.givenName + ' ' + profile.name.familyName;                    newUser.name = profile.name.givenName + ' ' + profile.name.familyName;                    newUser.email = profile.emails[0].value;                    newUser.save(err => {                        if (err) {                            console.log(err);                            throw err;                        }                        return done(null, newUser);                    });                }            });        });    }));

With this approach you can connect one profile with multiple social providers. However there is one downside. If the user registers a new profile for the first time through a social provider, he won't have a password because social providers don't give back password data (duh). He just needs to change (set) his password through his profile afterwards.