How do I update a FirebaseUser's phone number in firebase_auth?

Viewed 14752

In my Flutter app I use Firebase's phone number authentication as my main form of authentication. After authenticating, I create a user in my users collection with these details:

{
    phoneNumber: FirebaseAuth.instance.currentUser().phoneNumber,
    displayName: 'Comes from user textbox',
    ...
}

But say one day a user want's to change their phone number. How do I do this? Because I cannot simply change the user's phone number in the document, because the phone number needs to be authenticated. And after authentication, the user gets a new authUID. Which should then be a new user?

Could someone explain the logic behind a user that wants to keep their profile details but change their number.

2 Answers

In order to achieve this, you can use FirebaseUser.updatePhoneNumberCredential. This allows you to update the phone number of a user.

You would use it in the same manner that you also authenticated with phone number in the first place (using signInWithCredential), i.e. you retrieve a credential using FirebaseAuth.verifyPhoneNumber and pass the credential that you get from either verificationCompleted or your user when they enter the SMS code they received. I will only sketch out what this would look like as I assume that you know how to perform this task:

FirebaseAuth.instance.verifyPhoneNumber(
        phoneNumber: phoneNumber,
        timeout: const Duration(minutes: 2),
        verificationCompleted: (credential) async {
          await (await FirebaseAuth.instance.currentUser()).updatePhoneNumberCredential(credential);
          // either this occurs or the user needs to manually enter the SMS code
        },
        verificationFailed: null,
        codeSent: (verificationId, [forceResendingToken]) async {
          String smsCode;
          // get the SMS code from the user somehow (probably using a text field)
          final AuthCredential credential =
            PhoneAuthProvider.getCredential(verificationId: verificationId, smsCode: smsCode);
          await (await FirebaseAuth.instance.currentUser()).updatePhoneNumberCredential(credential);
        },
        codeAutoRetrievalTimeout: null);

When updatePhoneNumberCredential is called, you probably also want to update your database document. Alternatively, you could listen to onAuthStateChanged and update your document this way.

async function save(phone: string, e) {
    e.preventDefault();
    const { currentUser:fuser } = firebase.auth();
    if(fuser && fuser.phoneNumber !== phone) {
        try {
            const verifier = new firebase.auth.RecaptchaVerifier('recaptcha-container', {
                callback: (response) => console.log('callback', response),
                size: 'invisible',
            });
            const phoneProvider = new firebase.auth.PhoneAuthProvider();
            const id = await phoneProvider.verifyPhoneNumber(phone, verifier);
            const code = window.prompt('Bitte zugeschickten Code eingeben');
            const cred = firebase.auth.PhoneAuthProvider.credential(id, code);
            await fuser.updatePhoneNumber(cred);
            console.log('phone number changed', id, cred, fuser);
            setSuccess(true);
        } catch(e) {
            console.error(e);
        }
    }
}
Related