Authenticating with the Facebook auth provider creates a Firebase user with emailVerified: false. However, Facebook provides an email only if it's already been verified, so emailVerified should be true.
Our app also allows password authentication and requires email verification. Right now, this means users signing in with Facebook must verify their email, which isn't a great user experience. A temporary workaround would be to check the Firebase user's providerId and ignore the emailVerified if the provider is Facebook.
Environment:
Hmmm this issue does not seem to follow the issue template. Make sure you provide all the required information.
As far as I know, I don't think Facebook verifies all emails in every situation. However, Firebase Auth currently consider issuers of an email as verified. For example, Google is an issuer of @gmail.com emails. So users signing in with these accounts will have emailVerified. When future email issuer providers are supported, the emailVerified field will be true in that case too.
If you want to consider Facebook emails verified, you have the ability to do so with the Firebase Admin SDK. You can use updateUser API to toggle that flag to true for Facebook users.
You could do that with the help of Firebase Functions too. When onCreate event is triggered on user creation, you can check if the user is a Facebook user and update emailVerified to true.
Thanks, the onCreate trigger for a cloud function is a cleaner solution than what I proposed.
You're right: Facebook unfortunately doesn't seem to have a clear statement about whether emails are always verified. The answer is "probably, yes".
It would be convenient to have a built-in option in the Firebase auth console to trust the email verification from social providers, not just from email providers. This introduces some additional security risk if the social provider isn't completely trustworthy at email verification, but I think that's eliminated by the One account per email address setting: the worst case, in the rare event an email is mistakenly considered verified, is that the actual owner of the email will not be able to sign up with the app. This seems like a reasonable trade-off for many apps.
@kmjennison What if someone has unverified email (let's say a typo) and the actual owner will reset the password? He may then gain access to an account of a person signed in via i.e. facebook.
@merlinnot The case you described isn't specific to trusting that emails passed from Facebook are verified. If your app is trusting an unverified (wrong) email via password sign-in, there's risk that the real email owner will gain access to the user's account. In our app, we avoid this by requiring email verification before letting the user access the app.
This issue assumes that Facebook-provided emails are correct and verified—which seems reasonable but not necessarily guaranteed (see discussion above). Even if Facebook passes an unverified email, and the email is actually owned by an existing user who previously signed in via a password-based account, Firebase would not automatically link the accounts. I believe it would throw an auth/account-exists-with-different-credential error.
I think that the reason a customer would log in with Facebook credentials is to avoid all the annoyance of dealing with emails in the first place. Users are trusting our app with their Facebook credentials and thus we should consider emailVerified=true always. It's a pity we cannot set this up on Firebase...
Yeah, this is weird, should be fixed. Google facebook etc should have that attribute always in true
I'm sitting with this now, good to see it's still active! We're prompting all our new members, who signed up with email instead of social media to verify their email. As such, we're showing a seperate screen that is waiting for the user to verify their email. Even facebook sign ups are getting this screen (havent tested with google signups).
Also, could we get a Stream version of isEmailVerified, so that we can dynamically pop the screen once a "true" is received?
Any update on this ?
@bojeil-google In the even that that the account was created via a custom token and Facebook added as a provider, even after successfully setting emailVerified = true linking another provider will delete Facebook provider in my tests.
@bojeil-google Even if this isn't the default behavior, could it be an option in the Firebase Console for Facebook authentication? E.g., "Trust emails are already verified" with the default toggled to false.
@ncapdevi I reported the issue to our backend engineer. In your case, the Facebook provider should not be removed. It needs to be fixed in our backend.
We are using the onCreate function approach at the moment, but unfortunately this doesn't work when the user has first signed up using Google, then later on he forgot which provider he signup with and therefore select Facebook, in that case we also want to trust the email from Facebook instead of guiding the user to login using Google once again in order to link the accounts.
It could be nice, if we could select an option in the Firebase Auth console, that we want to trust the Facebook email. It is well known that Facebook verifies the emails, so it might be the case that Google doesn't trust that, but let it be up to the developer / the user of Firebase Auth to decide whether to trust the Facebook email is verified or not.
It is really odd, that Google does not take this serious, they say it is as designed / expected behaviour, they come up with several reasons for not trusting Facebook to verify the emails properly, saying that Facebook is not owner of the email domains etc., but at the same time they trust the emails from Apple SignIn. :/
@bojeil-google - unfortunately the approach you mention by setting emailVerified to true using the admin SDK, does not work, if the user has already signed in with the same email using Google and then later decides to sign in with Facebook instead.
I am running a solution with Google, Facebook, Email link and Apple SignIn. And I am really wondering why Firebase has decided to trust the emails from Apple, when not trusting the emails from Facebook. What is it that makes Google trust Apple more in this case?
Second, would it really be that big of a change in the Firebase SDK / Console to let the developer decide if they want emails from Facebook to be considered verified? So when you enable Facebook login you also flip a flag about that in Firebase Console.
Facebook also clearly state that it is verified, and that existing accounts with same emails should be merged: https://developers.facebook.com/docs/facebook-login/multiple-providers#associating2
Here's a sample onCreate cloud function that automatically marks FB users as emailVerified
exports.verifyFacebook = functions.auth.user().onCreate(async (snap) => {
if (!snap.providerData.find(d => d && d.providerId === 'facebook.com')) return
await admin.auth().updateUser(snap.uid, {
emailVerified: true
})
})
Note that I'm assuming that onCreate only one provider exists (plus I don't allow multiple providers in my case anyways)
Megha (Firebase engineer) here -
Facebook doesn't actually guarantee that the email has been verified:
Facebook’s documentation notes that when linking accounts, the developer should ensure that the email address passed in for Facebook login is valid when linking accounts (“If you use an email address as the unique credential which identifies each account, your app should verify that the email address associated with the person's Facebook account (and obtained during Facebook Login) is valid. You can do this by creating code in your app to send a verification email to the address obtained after Facebook Login (you will probably need to have this step as part of your regular login system anyway”).
Most helpful comment
@ncapdevi I reported the issue to our backend engineer. In your case, the Facebook provider should not be removed. It needs to be fixed in our backend.