Integration OAuth with Email/password in Firebase - firebase

I've been trying to setup an application that supports 3 types of Authentication:
- Email / password
- Google (OAuth)
- Facebook (OAuth)
In Firebase > Authentication > Sign-in methods, I've enabled the 3 options mentioned above.
In Firebase > Authentication > Advanced, I have the following set: "Prevent creation of multiple accounts with the same email address"
Just FYI, the password I use in my app to create an account with [Email/password] is different from my Google account, which is also different from my Facebook account (3 separate passwords - very real world scenario)
[Email/password]: john.doe#gmail.com, Password123
[Google]: john.doe#gmail.com, Password456
[Facebook]: john.doe#gmail.com, Password789
I want a user to Sign up with whatever provider they want to and then later on, link any other available sign-in / authentication options.
I can manage to properly setup [Email / Password] or the OAuth providers (Google and Facebook). But, when I try and integrate all 3 together, all hell breaks loose. Some noted errors:
Scenario A)
Create user with email / password / sign in / sign out (works fine)
Login with Google OAuth (associated to same email) as above, accounts are linked together / sign in / sign out
attempt to login with email/ password again -> ERROR
Google OAuth seems to have overridden the previous account settings
Scenario B)
Create user with email / password / sign in / sign out (works fine)
Login with Facebook OAuth (associated to same email) as above, accounts are linked together but get an error when attempting to login because my password used doesn't match my Facebook password. Yet this DOESN'T HAPPEN when I link my Google and Facebook accounts together. Why this issue with [Email/password] and OAuth providers?
I know there have been some updates / changes recently within Firebase, maybe the documentation / examples I checked weren't up-to-date. Has anyone successfully been able to [Email/password] authentication with OAuth providers as well? Can anyone provide a good example online or some recent documentation I can take a look at?
Btw, running code in Angular5 if that helps.
Thanks in advance for any help.
JB

Scenario A) happens because the email/password is unverified. The account is unlinked to prevent hijacking. For example I can claim another person's google email and create an email/password account. The owner of that Google account will then try to login to that account. I should lose access to it. To solve, try verifying the email after the email/password account is created. The verified account will not be unlinked.
Scenario B) This does not happen because of the passwords. Firebase doesn't have access to your Facebook or Google password. Are you sure you linking the account correctly? When you try to login with Facebook using the same email as existing email/password, you will get an error that the credential already exists (the error also returns the Facebook credential), you will need to first sign in to the existing email/password account and then link the Facebook credential to that account.

Related

Can Devise + Omniauth have several types of login?

I've used Devise as a standard authentication gem for other projects. In another project, I've used Devise + Omniauth for Twitter authentication.
In a new project I need my end users to be able to login via Twitter and Facebook or to be able to register via the app. In the future the user could link his accounts together. For example, his Twitter and Facebook account. Or, his Twitter and "native" account. "Native" being the account he registered with directly with the web app.
Is Devise capable of such? If so, how do we link the accounts of users together? What is the concept behind this? How does the app know which Facebook and Twitter account belong to which user?
Ideas and suggestions welcome.
EDIT:
I've been following http://railscasts.com/episodes/236-omniauth-part-2?autoplay=true and what i dont get is. If
user is signed out of app,
user has an account registered with app,
user signs in with a different service provider (facebook, twitter,
etc).
How does the app know how to link his new service provider with his already existing accounts?
Stackoverflow.com has this feature. But one service provider they are not including in their "multi-sign" on feature is Twitter. I'm guessing it's because Twitter doesn't expose the user's email through their API. While the other service providers (Facebook, Yahoo, Gmail) does.
Email is generally used to link all the accounts, but with Twitter, you can't get the email account.
Using the email is not really a good practice, because the user did not necessarily register to each service with the same email address.
Asking the user if he wants to use facebook/twitter/google/openid for authentication once he's logged in is the easiest way, and the more predictable for the user. You must prevent the effect "how does this website know my facebook account? Why are they tracking me?"
As a side note, the hardest part is not adding a new authentication method, but merging the accounts if the user, as an example, created one account with facebook, and one with twitter.
Devise is perfectly capable of that, but since every provider has its own token you
need a way to recognize the user no matter with which provider he chosen to log in.
The most common way to do it is by using the email field, you need to ask for the email
in each provider request, I personally don't like it because users can still have different emails in different providers.
To overcome this you can provide a option "connect my Facebook login with my Twitter login".
Please look for this screencasts, it will help you: OmniAuth
and OmniAuth part2
Recently I'he played with such problem as you have now. I goal was to implement many authentication solutions: Google, Twitter, Facebook .. at the same time - so user can login with multiple providers(like in Stackoverflow.com) and after logout he stay logged in with another service. I have implemented this by creating next schema (I have no my code right now but it should give you a clue):
class User
has_many :authentications
has_many :known_authentications
end
class Authentication
#implemented nearly as in Ryan's Railscasts (It keeps authorization info)
end
class KnownAuthentications
#has :provider, :user_id, :uid and :email columns. Here I keep all authorizations for registered user, that he ever had(so I can verify user by email and guess that this is the same user as logged in from different services). I fill this table when user registers with any service(Google, Twitter etc.).
end
When User logges in I check KnownAuthentifications table for current authorization service by email (OpenID service pass email with other parameters, OAuth - don't (so here I create fake email, say fake#email.com -> so Devise do not throughs exceptin)). Know I now that user logged in from Google is the same as currently logged in from Twitter.
I have this same question and although this isn't a complete solution (I don't think one really is 100% foolproof) this is what I'm building now.
Example: A site with username/password, Facebook, and Twitter for authentication.
A user comes to the site and wants to register. They register using Twitter for authentication. Twitter passes a bunch of information except email address. I am storing profile information (location, name, etc) that I think will be useful for comparison. The user is presented with a profile page immediately after authentication to verify profile information (they can remove any information they don't want stored). They also have the chance to add additional authentication methods (in this case, username/password and Facebook). The more you encourage them to link additional authentication methods while logged in the less trouble you will have with duplicated accounts. However it still exists as an edge case.
The edge case scenario goes like this: the user signs up with Twitter then immediately signs out and tries to sign in using Facebook. The sign in method detects that this is a new authentication and so it compares the oauth data from Facebook with existing profile information and tries to find matches. I then display the top 10 or so matches and ask the user to verify if they already exist so the account can be linked. Have the user sign in using Twitter and then link the Facebook account.
Obviously this would be easier and simpler if everyone used the same email address and Twitter would actually return an email address. But not everyone does so you have to handle this edge case in the best way you can - at this point I'll try the matching option and just push users to authenticate with other services as they sign up and fill in profile information.

Action on Google Test Account

Im virtually ready to send my Actions on Google App live for Google Home. It uses Account Linking to link a Google Account. I don't handle login as such, I just use the inbuilt routine to detect if the user is logged in and push them over to a Google Auth page which takes care of everything and I get the results back to generate a code.
The notes for submission say that if we're using account linking:
Your agent requires account linking so you must provide a username and
password for a test account. Please make sure that any provided
accounts are not real user accounts. This information will only be
used by the review team, and will not be visible to users.
What is not clear at this step, is what credentials I give to the review team to be able to test. I don't process any logins. Do I need to enable Email/Password authentication in Firebase then or something and on my OAuth page request Username/Password then authenticating with Firebase?
The answer lies in how you're authenticating the user:
push them over to a Google Auth page which takes care of everything
So you're expecting your users to login with some account (I assume you mean a Google account in this case) and you are either using the code that comes back as the auth code or getting the userid and using that to authenticate the user or something else along those lines.
Basically - you need to create whatever you expect them to do as if they were a user. If you're expecting your users to log in using a Google account - create a Google account for them to use. If you're expecting them to login with Email/Password auth in Firebase - set that up. But setup an account with however you expect your users to do so.

Lose password after sign in using Google provider

I have an Android app with use Firebase authentication using email and password. Recently added Google provider now my users can sign in wih his Google account, the problem is the following
There's an existing user example#gmail.com registered on my app, later the user sign in with his Google account Firebase automatically change the provider of the account from email to Google, the problem the user sign out and try to login with his email/password and got a message
The password is invalid or the user does not have a password
I understand why happens, but users (you know they are users) get frustrated because can't login with his email/password
There's some way to tell Firebase to keep the user password or when a user login with Google and this convertion happens in order to notify to user
Note My app only allow one account per email
I found there's a method fetchProvidersForEmail I asume I can build a flow over that method that check which provider have the user and allow the user chose if want to keep if old password by asking and linking account or just continue

Firebase : Authentication providers different email address

If I register with Facebook (x#x.com) and later log in with Google (y#y.com), but I do not have the same email address on both providers, there are 2 users created. How can I handle this situation?
Linking is typically used in three cases:
Automatically requested by the backend for security reasons: when a user signs in to google for example with email x#x and then logs out and tries to sign in with a new facebook account x#x. In this case the backend will not complete the second sign in without verifying that the second user is the same as the first user (since both use the same email). So in this case, the user has to sign to the google account and then link the second facebook account to the initial one.
Manually triggered by the developer: One common case here is that the user signs in to google with email x#x and remains signed in. The developer wants access to the user's facebook friends. So the developer will ask the user to link their facebook account to the already logged in google user.
Upgrading an anonymous user: Developer could automatically sign in users initially as anonymous and then prompt them to upgrade to a registered user. In this case you can call link on the anonymous user.
So auth.currentUser.link can be made on all kinds of users as long as the account you are linking is new and not already linked.
You'll want to use the Account Linking APIs to authenticate multiple providers for the same account. Docs for Web, Android, and iOS are available.

When using Omniauth for signing up with Facebook, why sometimes are the user's email not included in the authentication hash?

I am using Rails 3 + Devise 1.5 + OmniAuth via the omniauth-facebook gem to allow users to sign up for my app via Facebook.
I have everything working smoothly, except that once in a while, I have someone sign up for my app using Facebook, and the authentication hash doesn't contain the users email (although it includes many other attributes.) Again, most of the time I do get the email, but why is not included some of the time? Is there a way for a user to set his Facebook privacy settings in such a way that my app can obtain all sorts of info such as name, gender, and timezone, but not the email? I tried to make my own email in my Facebook profile private, but I was still able to log in to my app with Facebook.
Here's an example of a hash I received that's omitting the email (actual info censored):
"name"=>"XXXX XXXXXX", "first_name"=>"XXX", "last_name"=>"XXXXXX", "image"=>"http://graph.facebook.com/XXXXXXXXX/picture?type=square", "urls"=>{"Facebook"=>"http://www.facebook.com/XXXXXXXX"}}, "credentials"=>{"token"=>"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "expires_at"=>1329364800, "expires"=>true}, "extra"=>{"raw_info"=>{"id"=>"XXXXXXXX", "name"=>"XXXX XXXXXX", "first_name"=>"XXXX", "last_name"=>"XXXXXX", "link"=>"http://www.facebook.com/XXXXXXXXX", "username"=>"XXXXXXXXX", "gender"=>"female", "timezone"=>-5, "locale"=>"en_US", "verified"=>true, "updated_time"=>"2012-02-15T00:01:23+0000"}}}
Thanks very much in advance!
When a user is presented with Facebook's authentication dialog, they have the option to disallow sharing their email address with you before approving the authentication. Perhaps this is causing it to now show up in the auth hash.
Try revoking your test account, then reauthorizing through your app. At Facebook's dialog, it should list all of the permissions you request including email. At far right is a gray "X" that will disallow a certain permission. Try disallowing email and see if it reproduces what you're experiencing.
I believe this is a separate privacy control from the email privacy settings.
There are at least a couple of reasons this could happen:
The person signed up using a mobile phone number instead of an email address, so they have no email address registered with Facebook. (see "Facebook Login Basics" help page which confirms you can do this: https://www.facebook.com/help/418876994823287)
They have an email address registered with Facebook, but it isn't confirmed. According to this question: Is it possible to check if an email is confirmed on Facebook? Facebook won't return an unverified email address (though they had to provide a phone number to confirm the account before logging in). I haven't confirmed this behaviour though.

Resources