This code doesn't work for Twitter, because Twitter does not return email in the user data. Therefore, there is no way how to to connect Twitter account by email. I propose to exclude Twitter from your application until it is solved by Meteor (requestPermissions).
Also Github can have an account without email. So when user tries to login with GitHub without email, a new account is created.
Just create a new file oauth.js in server folder and copy paste the code below.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
isProdEnv = function () { | |
if (process.env.ROOT_URL == "http://localhost:3000") { | |
return false; | |
} else { | |
return true; | |
} | |
} | |
Accounts.loginServiceConfiguration.remove({ | |
service: 'google' | |
}); | |
Accounts.loginServiceConfiguration.remove({ | |
service: 'facebook' | |
}); | |
Accounts.loginServiceConfiguration.remove({ | |
service: 'twitter' | |
}); | |
Accounts.loginServiceConfiguration.remove({ | |
service: 'github' | |
}); | |
if (isProdEnv()) { | |
Accounts.loginServiceConfiguration.insert({ | |
service: 'github', | |
clientId: '00000', | |
secret: '00000' | |
}); | |
Accounts.loginServiceConfiguration.insert({ | |
service: 'twitter', | |
consumerKey: '00000', | |
secret: '00000' | |
}); | |
Accounts.loginServiceConfiguration.insert({ | |
service: 'google', | |
appId: '00000', | |
secret: '00000' | |
}); | |
Accounts.loginServiceConfiguration.insert({ | |
service: 'facebook', | |
appId: '00000', | |
secret: '00000' | |
}); | |
} else { | |
// dev environment | |
Accounts.loginServiceConfiguration.insert({ | |
service: 'github', | |
clientId: '11111', | |
secret: '11111' | |
}); | |
Accounts.loginServiceConfiguration.insert({ | |
service: 'twitter', | |
consumerKey: '11111', | |
secret: '11111' | |
}); | |
Accounts.loginServiceConfiguration.insert({ | |
service: 'google', | |
clientId: '11111', | |
secret: '11111' | |
}); | |
Accounts.loginServiceConfiguration.insert({ | |
service: 'facebook', | |
appId: '11111', | |
secret: '11111' | |
}); | |
} | |
Accounts.onCreateUser(function (options, user) { | |
if (user.services) { | |
if (options.profile) { | |
user.profile = options.profile | |
} | |
var service = _.keys(user.services)[0]; | |
var email = user.services[service].email; | |
if (!email) { | |
if (user.emails) { | |
email = user.emails.address; | |
} | |
} | |
if (!email) { | |
email = options.email; | |
} | |
if (!email) { | |
// if email is not set, there is no way to link it with other accounts | |
return user; | |
} | |
// see if any existing user has this email address, otherwise create new | |
var existingUser = Meteor.users.findOne({'emails.address': email}); | |
if (!existingUser) { | |
// check for email also in other services | |
var existingGitHubUser = Meteor.users.findOne({'services.github.email': email}); | |
var existingGoogleUser = Meteor.users.findOne({'services.google.email': email}); | |
var existingTwitterUser = Meteor.users.findOne({'services.twitter.email': email}); | |
var existingFacebookUser = Meteor.users.findOne({'services.facebook.email': email}); | |
var doesntExist = !existingGitHubUser && !existingGoogleUser && !existingTwitterUser && !existingFacebookUser; | |
if (doesntExist) { | |
// return the user as it came, because there he doesn't exist in the DB yet | |
return user; | |
} else { | |
existingUser = existingGitHubUser || existingGoogleUser || existingTwitterUser || existingFacebookUser; | |
if (existingUser) { | |
if (user.emails) { | |
// user is signing in by email, we need to set it to the existing user | |
existingUser.emails = user.emails; | |
} | |
} | |
} | |
} | |
// precaution, these will exist from accounts-password if used | |
if (!existingUser.services) { | |
existingUser.services = { resume: { loginTokens: [] }}; | |
} | |
// copy accross new service info | |
existingUser.services[service] = user.services[service]; | |
existingUser.services.resume.loginTokens.push( | |
user.services.resume.loginTokens[0] | |
); | |
// even worse hackery | |
Meteor.users.remove({_id: existingUser._id}); // remove existing record | |
return existingUser; // record is re-inserted | |
} | |
}); |
kinda think performing 4 queries (or one per service) could be optimized a bit..
ReplyDeleteIf the user doesn't have an email associated with the service, or the email associated with the service does not match on their external service then this breaks?
ReplyDeleteService Google does not have appId. It must be renamed to clientId.
ReplyDeleteThere is small problem in your code. It won't work. You expect "user" in Accounts.onCreateuser to have loginTokens as well, however, loginTokens are generated after user object is returned from this function back to Meteor. Hence, following line will cause error
ReplyDeleteexistingUser.services.resume.loginTokens.push(
user.services.resume.loginTokens[0]
);
You should comment these lines and it will work smoothly.