How to update phone number of a auth account by facebook provider - firebase

I have already authenticated with facebook provider in firebase. After authentication, I get back a user object with user details like name, email, and phoneNumber. The requirement is that I need to update phoneNumber as phone number I get back in user object is null. The phone number is crucial to the app I am building. There is this one option where I first authenticate the user with facebook provider and go to next screen and ask the user for a phone number and authenticate again with a phone number which basically creates a new user with phone number auth provider of the firebase after all this link account created by using facebook auth provider and phone number auth provider, but this method is kind of weird and kind of lot of work to be done just to store user's phone number, is there any other kind of method out there that I am missing? I really need to store user phone number and verify it but need to use facebook provider as the main authentication method.
I am using React Native (Expo) to build the mobile app.
The thing that I have already done, which has not worked for me.
let user = auth.currentUser;
user
.updateProfile({phoneNumber: <PhoneNumberInputFromUser>})
.then(() => {
this.navigateToMapView();
})
.catch(error => {
// TODO: Handle errors
console.log(error);
});
Using this does not throw error nor updates phoneNumber. But another weird thing here is that it goes to the then section of the code and navigates to map view.

I assume you are setting the Facebook phone number as the firebase user phone number. To securely do this:
On your server, use the facebook user's access token to query the facebook api for that user's phone number.
Assuming you know the corresponding Firebase user's uid:
admin.auth().updateUser(facebookUserFirebaseUid, {phoneNumber: facebookPhoneNumber})
.then(function(userRecord) {
// Return response to client to reload the user to pick up the changes.
})
.catch(function(error) {
// Error occurred.
});

Related

Firebase auth overriding user providers (email + password, phone) when signing-in with Google

As we have seen in another posts related to this situation and github issues, the expected behavior is that Google IDP overrides other non trusted providers related to the same email as an example, another account with the same email + password (non-verified).
Trying to understand Firebase Authentication one account per email address and trusted providers
Firebase Overwrites Signin with Google Account
https://github.com/firebase/firebase-ios-sdk/issues/5344
https://groups.google.com/g/firebase-talk/c/ms_NVQem_Cw/m/8g7BFk1IAAAJ
So, ok, according to google that's the expected behavior.
Our questions comes when we go to the documentation and there's an example of a user login in with google and getting this error auth/account-exists-with-different-credential just because there's another account created with email+password with the same email. Then, they recommend to catch the error, check the user email related login methods and ask the user to login with the other provider and then link to google.
Does this make sense ? If they say the expected behavior is that google as a trusted provider will override the others (this is what happens to us) how is possible that the case of the code example would even occur ?
https://firebase.google.com/docs/auth/web/google-signin#expandable-1
// Step 1.
// User tries to sign in to Google.
auth.signInWithPopup(new firebase.auth.GoogleAuthProvider()).catch(function(error) {
// An error happened.
if (error.code === 'auth/account-exists-with-different-credential') {
// Step 2.
// User's email already exists.
// The pending Google credential.
var pendingCred = error.credential;
// The provider account's email address.
var email = error.email;
// Get sign-in methods for this email.
auth.fetchSignInMethodsForEmail(email).then(function(methods) {
// Step 3.
// If the user has several sign-in methods,
// the first method in the list will be the "recommended" method to use.
if (methods[0] === 'password') {
// Asks the user their password.
// In real scenario, you should handle this asynchronously.
var password = promptUserForPassword(); // TODO: implement promptUserForPassword.
auth.signInWithEmailAndPassword(email, password).then(function(result) {
// Step 4a.
return result.user.linkWithCredential(pendingCred);
}).then(function() {
// Google account successfully linked to the existing Firebase user.
goToApp();
});
return;
}
// All the other cases are external providers.
// Construct provider object for that provider.
// TODO: implement getProviderForProviderId.
var provider = getProviderForProviderId(methods[0]);
// At this point, you should let the user know that they already have an account
// but with a different provider, and let them validate the fact they want to
// sign in with this provider.
// Sign in to provider. Note: browsers usually block popup triggered asynchronously,
// so in real scenario you should ask the user to click on a "continue" button
// that will trigger the signInWithPopup.
auth.signInWithPopup(provider).then(function(result) {
// Remember that the user may have signed in with an account that has a different email
// address than the first one. This can happen as Firebase doesn't control the provider's
// sign in flow and the user is free to login using whichever account they own.
// Step 4b.
// Link to Google credential.
// As we have access to the pending credential, we can directly call the link method.
result.user.linkAndRetrieveDataWithCredential(pendingCred).then(function(usercred) {
// Google account successfully linked to the existing Firebase user.
goToApp();
});
});
});
}
});
There's another example with the same structure in the flutter docs:
https://firebase.google.com/docs/auth/flutter/errors#handling_account-exists-with-different-credential_errors
Is this a contradiction in the documentation ? Again, if Firebase will always give priority to the trusted IDP (Google email) in this case, how is it possible to get this error if the other provider will be deleted (at least when having account linking activated - single account per email activated)
At least this is our case. We create an account with email & password and then try to login with google with the same email and what happens is that the email&password account is overwritten by the new google provider.
Unfortunately, you can't change it. If a user with #gmail.com email and password authentication updates their profile picture and then later logins with Google then the profile picture and any other information will be overwritten with the data from Google. The only option is to create a user record in the database that gets populated with the user data (displayName, photoURL etc) when the user is created for the first time. You then always use the data from this record instead of the default user object that is returned by the authentication.
The other advantage of creating a record is that you can attach a listener to it. That way if the user changes their details then it gets reflected everywhere.

Ionic Authentication

I have a use case where I need to signup incoming customers in following way
The customer visits the site.
If the customer is new, then he will register himself on the site with email and phone number.
After this, the admin will send the email with OTP to that customer.
Once the customer has received the OTP, he can signin to the system and set new password.
I am using Firebase as backend for this and Ionic in the frontend.
I am confused as to how should I go for implementing this?
I was thinking of storing new users in real-time database and once the admin has confirmed then trigger a function to send OTP via mail.
Any suggestions on this?
I'm hoping your using angular
Use Firebase Auth
Set default route to login screen
When customer enters check the firebase auth state if authenticated proceed to home screen
Note: firebase.auth().onAuthStateChanged((user) => {}) can recognize user if previously logged in.
I not authenticated show login screen and register screens.
Use Firebase auth so it have a parameter called "verified" set to false by default.
when admin verifies set verified to true and trigger a cloud function to send Otp.

how to know if phone number already linked with the password account in firebase web before OTP sent to user

I am creating an ionic application with firebase authentication. I provided 'facebook login' and 'password authentication' feature. When the user tries to login via the above two features, I want them to link their phone number with their Facebook or password authentication account. I had implemented the feature of linking phone number with their account.
My requirement here is: I want to check if the phone number they are trying to link is already linked by some other user in the firebase User or not. If not I allow them to link else I won't. Also, I want this result before OTP sent to the user.
this.confirmationResult = this.auth.userCredential.user. linkWithPhoneNumber(this.phoneNumber, this.appVerifier);
I expect the above code should return an error if the phone number is already linked with some other account.
But, It allows sending the OTP to the user's phone number and then prompts me to provide the code sent to the phone number.
Also, I can able to receive the error code after verify the OTP like
"auth/credential-already-in-use". I want this before code sent to the user's phone number. Please help me to achieve this scenario.
You can use the Firebase Admin SDK to lookup whether a user with a phone number already exists.
Here is an example with Node.js
admin.auth().getUserByPhoneNumber(phoneNumber)
.then(function(userRecord) {
// A user with the phone number already exists.
// You can also get other information related to the user from the
// userRecord.
})
.catch(function(error) {
console.log('Error fetching user data:', error);
});

Storing phone number in user info/user profile without authentication in Firebase

I'm siging in users with the Email/Password method on Firebase. I'm not interested in switching to phone authentication. That being said, I'd like to store the users phone number in their profile for later access.
I know I can store it like so:
Users/UID/PhoneNumber: XXXXXX
But I'd like to be able to access it at a later date without having to query for that user id. Rather I'd like to store it so I can get at it through currentUser.phoneNumber or something similar.
I know there updateProfile which takes a displayName and profilePic but the documentation doesn't seem to allow phoneNumber. Is there anyway to achieve this?
You can't get the user phone doing something like this:
mAuth = FirebaseAuth.getCurrentUser().getPhoneNumber();
as you cannot access directly the user phone without implementing Firebase Phone Auth.
Since you don't care if that number is from that person, a workaround would be doing an AlertDialog or an EditText to prompt the user to type the desired number you want to store, and yes, you will need to query it each time since you are not getting it from Auth.
The only way possible of getting the user phone number in the userInfo as you say without querying the database is implementing Phone Auth.
Doing the workaround there is no guarantee that the phone number
entered by the user is the right one
Consider using the admin sdk updateUser API: https://firebase.google.com/docs/auth/admin/manage-users#update_a_user
admin.auth().updateUser(uid, {
phoneNumber: "+11234567890",
}).then(function(userRecord) {
// User updated. You can now get this from client:
// FirebaseAuth.getCurrentUser().getPhoneNumber();
}).catch(function(error) {
// Error occurred.
});

How to implemet whatsapp type phone number authorization in Firebase

Following is what I am trying to achieve:
User installs the app
On its first launch, user will be asked to specify phone number and Name
Phone number gets verified by invoking REST API of OTP service providers
Once 2 Factor Authentication gets complete, I will create the user in Firebase database with its mobile number and Name as attribute to unique phone number
Problem: Now, what I am not getting is how to authenticate user with only phone number, as I want to track all his activities under his/her mobile number.
function showLoginBox() {
...
// Do whatever DOM operations you need to show the login/registration box.
$("#registerButton").on("click", function() {
var email = $("#email").val();
var phone = $("#phone").val();
// Invoke REST API to generate OTP/ Miss call
// Read OTP or user enters the OTP
// Invoke REST API to complete 2FA (Two factor authentication)
// Add the user information to Firebase
authClient.createUser(email, phone, name, function(error, user) {
if (!error) {
doLogin(user);
} else {
alert(error);
}
});
});
}
Now doLogin() function will be passed user object and I can get the user details, but how do I login now.. as I cannot invoke email/password combination or Anonymous login.
I even saw the JWT (JSON web token) thing, but it is mentioned under custom login, not sure whether it make sense
Can I do following:
- Save the verified mobile number (after 2FA) into local database (window.localstorage)
- Read local storage and send the mobile number with every subsequent call
But unless, I will invoke the authentication, how do I implement security/authorization, so as this mobile number can access only its related data.
Can anyone help me to figure out following things:
- How do I login the user with his mobile number only
- How can I track each and every activity performed by the user by his mobile number (Here mobile number is his user id)
Thanks in advance.

Resources