My app implements the Google and Facebook login. The trouble is that there seems to be no differentiation between “logging in” with Google and “registering” with google - they both go through the oauth process and create an account if one does not already exist.
I have users who register with my service using the normal email and password mechanism (say with a hotmail account), then discover the “Login with Google” button and think they can press that button and get logged in under their hotmail account! Result - two logins and confusion reigns.
I really only want to create a new account when the user clicks the “register with google” button and refuse login with “login with google” when the email does not exists.
Since you actually hand over the login process to Google, you only get feedback afterwards.
Which means that you have to go at it the other way around: Upon creation of a new account, you have to see if there’s another “native” account using the same email address. And then link the two.
Thanks for your reply - the problem is that it’s not the same email (you can’t have two accounts using the same email). I can’t reliably detect that two differently created accounts with different emails are, in fact, the same intended account…
If it’s not the same email then I’m not sure how you intend to block the OAuth request in the first place?
And I’m moderately certain that you can have two accounts with the same email address - because the OAuth accounts store the login data differently from the “native” ones. And as far as I know, the OAuth accounts are not queried when looking up email addresses.
Hi again, You’re right that the oAuth happens entirely independently - and I’m not really expecting to block that part of it. It’s just that, when it returns we have a google authenticated user that, when Meteor looks to see if that user (i.e. their email) is in the user table, it will create a new user if its not. I don’t want it to do that. I want it to reject the attempted login because the user does not exist! I only want it to create a user if the oAuth sequence began with a “Register with google” initiation from the app.
I don’t think there’s a flag that lets you choose whether to create an account or not in the accounts-oauth package. So what you’ll have to do is use a local copy of the package, which meteor will use instead of the online one.
Yes, I understand all this - excellent guidance thank you. Only issue is that, at this point in the code I do not know whether the oAuth was initiated by clicking the “Register with google” button (signup) or with the “Login with Google” button (signin). For the former I do want to create an account, for the latter I do not!
@coagmano’s advice to copy the package and edit it is correct.
Otherwise, you have a few options:
You can have users always type in their email addresses, and check to see what their login/signup options are. This would start the signup/login flow with one field, “Your E-Mail Address.”
You should always show the social login buttons, and then add a URL that says, “Create an account instead.” So that it takes two steps to create an e-mail and password based account.
Note, in Meteor, you can always promote social accounts to have passwords by simply adding the password service entry in the user document. A good flow is to ask users to set a password.
I think the most confusing thing for many normal people is that Google means e-mail to them, even though they have hotmail accounts.
This is a bit more complicated then, thanks to the flow of oauth
My suggestion is to set a flag to keep track of if this is a login or signup attempt, pass the flag through to the server in the accounts-oauth package:
Then on the server, check options.oauth.isSignup before doing the same test as suggested in the previous answer
Setting the flag might be annoying, since some oauth services redirect the whole page to get user permission, in which case you can probably use OAuth.saveDataForRedirect and OAuth.getDataAfterRedirect to save the flag
I’ve run into this exact same issue a couple years ago and this is basically how I fixed it, although I don’t use the higher-level accounts-oauth package so I had to register a new login handler to which I pass a parameter, when calling Accounts.callLoginMethod, to specify if I’m in a login or signup flow. I really think it’s the best solution here.
And in oauth_server.js I inserted this before the final call to Accounts.updateOrCreateUserFromExternalService:
if (options.oauth.routeName=='signin') {
if (!Accounts.findUserByEmail(result.serviceData.email)) {
return {
type: "oauth",
error: new Meteor.Error(403,"No matching user found")
};
}
}
Method parameters are checked so I had to modify the check at the top of the file: