11 thoughts on “Firebase Phone Number Auth integration

  1. I’ve been looking into this today. I’ll have to speak internally about how to actually implement this (more best practice). The aim of this lib is to try and replicate the web SDK, however I don’t think it’ll be possible here.

    1. On the Web docs there’s no need for steps 1-3.
    2. signInWithPhoneNumber takes a phoneNumber & appVerifier (where appVerifier is redundant on the device).
    3. The native SDKs (at least on Android) takes a verifyPhoneNumber. It can also do things like auto detection. The response of which, can be directly passed into signInWithCredential.

    @chrisbianca @Salakar How do you suggest dealing with the following workflow:

    After calling verifyPhoneNumber, we return a promise which would resolve on onVerificationCompleted (Instantly verified or auto detected). The issue is though, there’s an optional onCodeSent which would prompt the user to enter the code manually (as it’s not been detected automagically). How would that fit into the API?

    firebase.auth().verifyPhoneNumber('+441234567')
      .then((credential) => {}) // onVerificationCompleted
      .catch(() => {});

    That may potentially never get called, as it’s hit the onCodeSent block. We could add a method like verifyPhoneCode or something, but then how would the user know whether to use this or not.

  2. Hello, I successfully got it working for iOS. Unfortunately I don’t have the time for a PR but I will describe how I went on. First, the NativeModule (my module is called WHOFirebaseAuth here)

    //
    //  WHOFirebaseAuth.m
    //  WhoCaresAppNew
    //
    //  Created by Enes Kaya on 29.05.17.
    //  Copyright © 2017 Facebook. All rights reserved.
    //
    
    #import "WHOFirebaseAuth.h"
    #import <FirebaseAuth/FirebaseAuth.h>
    
    @implementation WHOFirebaseAuth
    
    RCT_EXPORT_MODULE();
    
    RCT_EXPORT_METHOD(verifyPhoneNumber:(NSString*) userInput
                      callback:(RCTResponseSenderBlock) callback)
    {
        [[FIRPhoneAuthProvider provider]
         verifyPhoneNumber: userInput
         completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
           
           NSLog(@"WHOFirebaseAuth: %%@", userInput);
           
          if (error) {
            callback(@[error.localizedDescription, @"ERROR"]);
            NSLog(@"WHOFirebaseAuth: %%@", error.localizedDescription);
          } else {
            // Sets the verficiationID in UserDefaults for later usage
            NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
            [defaults setObject:verificationID forKey:@"authVerificationID"];
            
            callback(@[[NSNull null], verificationID]);
          }
          
        }];
    }
    
    RCT_EXPORT_METHOD(getVerificationId:(RCTResponseSenderBlock)callback)
    {
      NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
      NSString *verificationID = [defaults stringForKey:@"authVerificationID"];
      callback(@[[NSNull null], verificationID]);
    }
    
    @end

    You call it like this in your RN project:

    const WHOFirebaseAuth = NativeModules.WHOFirebaseAuth
    ...
    static sendVerificationCodeTo(phoneNumber) {
       return new Promise((resolve, reject) => {
    	WHOFirebaseAuth.verifyPhoneNumber(
    		phoneNumber,
    		(error, verificationID) => {
    			if (!error) {
    				resolve({
    					error: null,
    					verificationID: verificationID
    				})
    			} else {
    				reject({
    					error,
    					verificationID: null
    				})
    			}
    		}
    	)
       })
    }
    ...

    After that, if it was successful, the user get’s the code sent via SMS. Then you can log in like so:

    	/**
       * Signs the user in with PhoneAuth credential.
       *
       * @param  {[type]} verificationID The verificationID returned by this.sendVerificationCodeTo
       * @param  {[type]} code           The code which was sent via SMS
       * @return {[type]}                firebase.Promise containing non-null firebase.User
       */
    	static signInWithPhoneAuth(verificationID, code) {
    		var credential = firebase.auth.PhoneAuthProvider.credential(
    			verificationID,
    			code
    		)
    
    		return firebase.auth().signInWithCredential(credential)
    	}

    So, basically it’s a mix between the native SDK and the JS SDK. Remember to install Firebase/Auth via CocoaPods in version >4.0.0.

    Hope that helps, for me it’s working perfectly.

  3. I was just about to post a version of myself.
    What I did slightly different was I used promises rather than callbacks

    RCT_EXPORT_METHOD(verifyPhone:(NSString *)userInput
                      resolver:(RCTPromiseResolveBlock)resolve
                      rejecter:(RCTPromiseRejectBlock)reject)
    {
      [[FIRPhoneAuthProvider provider]
       verifyPhoneNumber:userInput
       completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
          if (error) {
             reject(@"Error on Phone Verification", @"Phone can't be verified", error);
          }
          NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
          [defaults setObject:verificationID forKey:@"authVerificationID"];
          resolve(verificationID);
      }];
    }
    
  4. I’m back in the country now, so should be able to pick back up on this over the next few days. I’ll try and pick up on the questions above that haven’t already been answered:

    @subugwriter Thanks for raising the linking issue. Auto-verify on Android has been a right pain to deal with in a cross platform manner. What I’m going to try and do is the following:

    1. Update the current signInWithPhoneNumber to link the phone credential automatically if the user is already signed in.

    2. Expose a new verifyPhoneNumber endpoint to the API which will expose the underlying API more explicitly, e.g. onCodeSent, onAutoVerified, etc, so that the user can do what they want should they need anything more custom.

    @javamonn Thanks for mentioning FirebaseUI. This is certainly an option, however by using FirebaseUI there are some limitations – namely, that it will import all the underlying Firebase modules regardless of whether they’re being used in the rest of the app or not. Also, React Native makes it so easy to build UIs, that it shouldn’t really be necessary. Hopefully when the above changes I’ve proposed are made, this will render FirebaseUI unnecessary. I’m also not sure how well the new multi app support would translate across between react-native-firebase and FirebaseUI

    @maraujop Sounds like you’ve not got the required Android libraries being imported correctly. I’d need the rest of the error message to be able to help any further than that.

    @faahmad I’d suggest you debug your verifyCode method and see whether you’re correctly setting confirmResult in your reducer.

    @bintoll Documentation will be firmed up once we’ve agreed on the final implementation. We wanted to find out how everybody was using the library and highlight the edge cases, e.g. linking the credential, before we spent too much time there.

  5. All,

    I’ve just pushed up the verifyPhoneNumber implementation (as @chrisbianca mentioned above). Source code.

    This implementation gives you full control of the phone number verification flow on either platform as well as a flexible api to suite any UI flow and should be familiar to use if you’ve used things like storage upload tasks / database on listeners.


    Cross Platform Example

    This code snippet covers all scenarios for both android and iOS, how you implement this is entirely up to you. A simpler iOS only usage example can be found below this example.

    firebase.auth()
      .verifyPhoneNumber('+441234567890')
      .on('state_changed', (phoneAuthSnapshot) => {
        // How you handle these state events is entirely up to your ui flow and whether
        // you need to support both ios and android. In short: not all of them need to
        // be handled - it's entirely up to you, your ui and supported platforms.
    
        // E.g you could handle android specific events only here, and let the rest fall back
        // to the optionalErrorCb or optionalCompleteCb functions
        switch (phoneAuthSnapshot.state) {
          // ------------------------
          //  IOS AND ANDROID EVENTS
          // ------------------------
          case firebase.auth.PhoneAuthState.CODE_SENT: // or 'sent'
            console.log('code sent');
            // on ios this is the final phone auth state event you'd receive
            // so you'd then ask for user input of the code and build a credential from it
            break;
          case firebase.auth.PhoneAuthState.ERROR: // or 'error'
            console.log('verification error');
            console.log(phoneAuthSnapshot.error);
            break;
    
          // ---------------------
          // ANDROID ONLY EVENTS
          // ---------------------
          case firebase.auth.PhoneAuthState.AUTO_VERIFY_TIMEOUT: // or 'timeout'
            console.log('auto verify on android timed out');
            // proceed with your manual code input flow, same as you would do in
            // CODE_SENT if you were on IOS
            break;
          case firebase.auth.PhoneAuthState.AUTO_VERIFIED: // or 'verified'
            // auto verified means the code has also been automatically confirmed as correct/received
            // phoneAuthSnapshot.code will contain the auto verified sms code - no need to ask the user for input.
            console.log('auto verified on android');
            console.log(phoneAuthSnapshot);
            // Example usage if handling here and not in optionalCompleteCb:
            // const { verificationId, code } = phoneAuthSnapshot;
            // const credential = firebase.auth.PhoneAuthProvider.credential(verificationId, code);
    
            // Do something with your new credential, e.g.:
            // firebase.auth().signInWithCredential(credential);
            // firebase.auth().linkWithCredential(credential);
            // etc ...
            break;
        }
      }, (error) => {
        // optionalErrorCb would be same logic as the ERROR case above,  if you've already handed
        // the ERROR case in the above observer then there's no need to handle it here
        console.log(error);
        // verificationId is attached to error if required
        console.log(error.verificationId);
      }, (phoneAuthSnapshot) => {
        // optionalCompleteCb would be same logic as the AUTO_VERIFIED/CODE_SENT switch cases above
        // depending on the platform. If you've already handled those cases in the observer then
        // there's absolutely no need to handle it here.
    
        // Platform specific logic:
        // - if this is on IOS then phoneAuthSnapshot.code will always be null
        // - if ANDROID auto verified the sms code then phoneAuthSnapshot.code will contain the verified sms code
        //   and there'd be no need to ask for user input of the code - proceed to credential creating logic
        // - if ANDROID auto verify timed out then phoneAuthSnapshot.code would be null, just like ios, you'd
        //   continue with user input logic.
        console.log(phoneAuthSnapshot);
      });
    // optionally also supports .then & .catch instead of optionalErrorCb &
    // optionalCompleteCb (with the same resulting args)

    Basic Example

    The api is flexible enough to not force those of you that only need to support one platform (in this case iOS) into a wall of code.

    Whilst this example makes use of the optional resulting promise, you can still however use the observer api instead and handle CODE_SENT and ERROR events individually like in the above detailed example – again it’s entirely up to you.

    firebase.auth()
      .verifyPhoneNumber('+441234567890')
      .then((phoneAuthSnapshot) => {
        console.log(phoneAuthSnapshot);
        // wait / get users code input then:
        // const { verificationId } = phoneAuthSnapshot;
        // const { codeInput } = this.state; // tied to your input box, for example
        // const credential = firebase.auth.PhoneAuthProvider.credential(verificationId, codeInput);
    
        // Do something with your new credential, e.g.:
        // firebase.auth().signInWithCredential(credential);
        // firebase.auth().linkWithCredential(credential);
      })
      .catch((error) => {
        console.log(error);
        console.log(error.verificationId);
      });

    As verifyPhoneNumber covers full support for the firebase phone auth api I think we close to closing this issue 🎉, just some further testing required by us internally and also any feedback you guys may have?

    As for signInWithPhoneNumber I think we’ll leave this in it’s current state (without auto linking) – even though verifyPhoneNumber negates the need for it – for those of you who’d prefer to use it (unless you tell us otherwise?).

    Thanks again all for helping us work through the implementation.

  6. Hey all, this is now part of the full v3 release (with Cloud Firestore 🎉 ) that we pushed out to npm yesterday. I’ll be closing this issue now. I’m still working on the docs but for now please use this thread (#119 (comment) specifically) for implementation guides.

    Please raise any new issues in separate github issues going forward. If you have queries / or want to continue discussing this further you can join us on discord – this thread takes far too long to load now 🙈

    Thanks

Comments are closed.

12 thoughts on “Firebase Phone Number Auth integration

  1. I’ve been looking into this today. I’ll have to speak internally about how to actually implement this (more best practice). The aim of this lib is to try and replicate the web SDK, however I don’t think it’ll be possible here.

    1. On the Web docs there’s no need for steps 1-3.
    2. signInWithPhoneNumber takes a phoneNumber & appVerifier (where appVerifier is redundant on the device).
    3. The native SDKs (at least on Android) takes a verifyPhoneNumber. It can also do things like auto detection. The response of which, can be directly passed into signInWithCredential.

    @chrisbianca @Salakar How do you suggest dealing with the following workflow:

    After calling verifyPhoneNumber, we return a promise which would resolve on onVerificationCompleted (Instantly verified or auto detected). The issue is though, there’s an optional onCodeSent which would prompt the user to enter the code manually (as it’s not been detected automagically). How would that fit into the API?

    firebase.auth().verifyPhoneNumber('+441234567')
      .then((credential) => {}) // onVerificationCompleted
      .catch(() => {});

    That may potentially never get called, as it’s hit the onCodeSent block. We could add a method like verifyPhoneCode or something, but then how would the user know whether to use this or not.

  2. Hello, I successfully got it working for iOS. Unfortunately I don’t have the time for a PR but I will describe how I went on. First, the NativeModule (my module is called WHOFirebaseAuth here)

    //
    //  WHOFirebaseAuth.m
    //  WhoCaresAppNew
    //
    //  Created by Enes Kaya on 29.05.17.
    //  Copyright © 2017 Facebook. All rights reserved.
    //
    
    #import "WHOFirebaseAuth.h"
    #import <FirebaseAuth/FirebaseAuth.h>
    
    @implementation WHOFirebaseAuth
    
    RCT_EXPORT_MODULE();
    
    RCT_EXPORT_METHOD(verifyPhoneNumber:(NSString*) userInput
                      callback:(RCTResponseSenderBlock) callback)
    {
        [[FIRPhoneAuthProvider provider]
         verifyPhoneNumber: userInput
         completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
           
           NSLog(@"WHOFirebaseAuth: %%@", userInput);
           
          if (error) {
            callback(@[error.localizedDescription, @"ERROR"]);
            NSLog(@"WHOFirebaseAuth: %%@", error.localizedDescription);
          } else {
            // Sets the verficiationID in UserDefaults for later usage
            NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
            [defaults setObject:verificationID forKey:@"authVerificationID"];
            
            callback(@[[NSNull null], verificationID]);
          }
          
        }];
    }
    
    RCT_EXPORT_METHOD(getVerificationId:(RCTResponseSenderBlock)callback)
    {
      NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
      NSString *verificationID = [defaults stringForKey:@"authVerificationID"];
      callback(@[[NSNull null], verificationID]);
    }
    
    @end

    You call it like this in your RN project:

    const WHOFirebaseAuth = NativeModules.WHOFirebaseAuth
    ...
    static sendVerificationCodeTo(phoneNumber) {
       return new Promise((resolve, reject) => {
    	WHOFirebaseAuth.verifyPhoneNumber(
    		phoneNumber,
    		(error, verificationID) => {
    			if (!error) {
    				resolve({
    					error: null,
    					verificationID: verificationID
    				})
    			} else {
    				reject({
    					error,
    					verificationID: null
    				})
    			}
    		}
    	)
       })
    }
    ...

    After that, if it was successful, the user get’s the code sent via SMS. Then you can log in like so:

    	/**
       * Signs the user in with PhoneAuth credential.
       *
       * @param  {[type]} verificationID The verificationID returned by this.sendVerificationCodeTo
       * @param  {[type]} code           The code which was sent via SMS
       * @return {[type]}                firebase.Promise containing non-null firebase.User
       */
    	static signInWithPhoneAuth(verificationID, code) {
    		var credential = firebase.auth.PhoneAuthProvider.credential(
    			verificationID,
    			code
    		)
    
    		return firebase.auth().signInWithCredential(credential)
    	}

    So, basically it’s a mix between the native SDK and the JS SDK. Remember to install Firebase/Auth via CocoaPods in version >4.0.0.

    Hope that helps, for me it’s working perfectly.

  3. I was just about to post a version of myself.
    What I did slightly different was I used promises rather than callbacks

    RCT_EXPORT_METHOD(verifyPhone:(NSString *)userInput
                      resolver:(RCTPromiseResolveBlock)resolve
                      rejecter:(RCTPromiseRejectBlock)reject)
    {
      [[FIRPhoneAuthProvider provider]
       verifyPhoneNumber:userInput
       completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
          if (error) {
             reject(@"Error on Phone Verification", @"Phone can't be verified", error);
          }
          NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
          [defaults setObject:verificationID forKey:@"authVerificationID"];
          resolve(verificationID);
      }];
    }
    
  4. I’m back in the country now, so should be able to pick back up on this over the next few days. I’ll try and pick up on the questions above that haven’t already been answered:

    @subugwriter Thanks for raising the linking issue. Auto-verify on Android has been a right pain to deal with in a cross platform manner. What I’m going to try and do is the following:

    1. Update the current signInWithPhoneNumber to link the phone credential automatically if the user is already signed in.

    2. Expose a new verifyPhoneNumber endpoint to the API which will expose the underlying API more explicitly, e.g. onCodeSent, onAutoVerified, etc, so that the user can do what they want should they need anything more custom.

    @javamonn Thanks for mentioning FirebaseUI. This is certainly an option, however by using FirebaseUI there are some limitations – namely, that it will import all the underlying Firebase modules regardless of whether they’re being used in the rest of the app or not. Also, React Native makes it so easy to build UIs, that it shouldn’t really be necessary. Hopefully when the above changes I’ve proposed are made, this will render FirebaseUI unnecessary. I’m also not sure how well the new multi app support would translate across between react-native-firebase and FirebaseUI

    @maraujop Sounds like you’ve not got the required Android libraries being imported correctly. I’d need the rest of the error message to be able to help any further than that.

    @faahmad I’d suggest you debug your verifyCode method and see whether you’re correctly setting confirmResult in your reducer.

    @bintoll Documentation will be firmed up once we’ve agreed on the final implementation. We wanted to find out how everybody was using the library and highlight the edge cases, e.g. linking the credential, before we spent too much time there.

  5. All,

    I’ve just pushed up the verifyPhoneNumber implementation (as @chrisbianca mentioned above). Source code.

    This implementation gives you full control of the phone number verification flow on either platform as well as a flexible api to suite any UI flow and should be familiar to use if you’ve used things like storage upload tasks / database on listeners.


    Cross Platform Example

    This code snippet covers all scenarios for both android and iOS, how you implement this is entirely up to you. A simpler iOS only usage example can be found below this example.

    firebase.auth()
      .verifyPhoneNumber('+441234567890')
      .on('state_changed', (phoneAuthSnapshot) => {
        // How you handle these state events is entirely up to your ui flow and whether
        // you need to support both ios and android. In short: not all of them need to
        // be handled - it's entirely up to you, your ui and supported platforms.
    
        // E.g you could handle android specific events only here, and let the rest fall back
        // to the optionalErrorCb or optionalCompleteCb functions
        switch (phoneAuthSnapshot.state) {
          // ------------------------
          //  IOS AND ANDROID EVENTS
          // ------------------------
          case firebase.auth.PhoneAuthState.CODE_SENT: // or 'sent'
            console.log('code sent');
            // on ios this is the final phone auth state event you'd receive
            // so you'd then ask for user input of the code and build a credential from it
            break;
          case firebase.auth.PhoneAuthState.ERROR: // or 'error'
            console.log('verification error');
            console.log(phoneAuthSnapshot.error);
            break;
    
          // ---------------------
          // ANDROID ONLY EVENTS
          // ---------------------
          case firebase.auth.PhoneAuthState.AUTO_VERIFY_TIMEOUT: // or 'timeout'
            console.log('auto verify on android timed out');
            // proceed with your manual code input flow, same as you would do in
            // CODE_SENT if you were on IOS
            break;
          case firebase.auth.PhoneAuthState.AUTO_VERIFIED: // or 'verified'
            // auto verified means the code has also been automatically confirmed as correct/received
            // phoneAuthSnapshot.code will contain the auto verified sms code - no need to ask the user for input.
            console.log('auto verified on android');
            console.log(phoneAuthSnapshot);
            // Example usage if handling here and not in optionalCompleteCb:
            // const { verificationId, code } = phoneAuthSnapshot;
            // const credential = firebase.auth.PhoneAuthProvider.credential(verificationId, code);
    
            // Do something with your new credential, e.g.:
            // firebase.auth().signInWithCredential(credential);
            // firebase.auth().linkWithCredential(credential);
            // etc ...
            break;
        }
      }, (error) => {
        // optionalErrorCb would be same logic as the ERROR case above,  if you've already handed
        // the ERROR case in the above observer then there's no need to handle it here
        console.log(error);
        // verificationId is attached to error if required
        console.log(error.verificationId);
      }, (phoneAuthSnapshot) => {
        // optionalCompleteCb would be same logic as the AUTO_VERIFIED/CODE_SENT switch cases above
        // depending on the platform. If you've already handled those cases in the observer then
        // there's absolutely no need to handle it here.
    
        // Platform specific logic:
        // - if this is on IOS then phoneAuthSnapshot.code will always be null
        // - if ANDROID auto verified the sms code then phoneAuthSnapshot.code will contain the verified sms code
        //   and there'd be no need to ask for user input of the code - proceed to credential creating logic
        // - if ANDROID auto verify timed out then phoneAuthSnapshot.code would be null, just like ios, you'd
        //   continue with user input logic.
        console.log(phoneAuthSnapshot);
      });
    // optionally also supports .then & .catch instead of optionalErrorCb &
    // optionalCompleteCb (with the same resulting args)

    Basic Example

    The api is flexible enough to not force those of you that only need to support one platform (in this case iOS) into a wall of code.

    Whilst this example makes use of the optional resulting promise, you can still however use the observer api instead and handle CODE_SENT and ERROR events individually like in the above detailed example – again it’s entirely up to you.

    firebase.auth()
      .verifyPhoneNumber('+441234567890')
      .then((phoneAuthSnapshot) => {
        console.log(phoneAuthSnapshot);
        // wait / get users code input then:
        // const { verificationId } = phoneAuthSnapshot;
        // const { codeInput } = this.state; // tied to your input box, for example
        // const credential = firebase.auth.PhoneAuthProvider.credential(verificationId, codeInput);
    
        // Do something with your new credential, e.g.:
        // firebase.auth().signInWithCredential(credential);
        // firebase.auth().linkWithCredential(credential);
      })
      .catch((error) => {
        console.log(error);
        console.log(error.verificationId);
      });

    As verifyPhoneNumber covers full support for the firebase phone auth api I think we close to closing this issue 🎉, just some further testing required by us internally and also any feedback you guys may have?

    As for signInWithPhoneNumber I think we’ll leave this in it’s current state (without auto linking) – even though verifyPhoneNumber negates the need for it – for those of you who’d prefer to use it (unless you tell us otherwise?).

    Thanks again all for helping us work through the implementation.

  6. @maraujop this has been pushed up for android, you should be good to go now for android – will sort ios shortly.

    My UI skills aren’t amazing, but here’s a gif of android working with auto verify included, it’s pretty quick:

    boop

  7. Hey all, this is now part of the full v3 release (with Cloud Firestore 🎉 ) that we pushed out to npm yesterday. I’ll be closing this issue now. I’m still working on the docs but for now please use this thread (#119 (comment) specifically) for implementation guides.

    Please raise any new issues in separate github issues going forward. If you have queries / or want to continue discussing this further you can join us on discord – this thread takes far too long to load now 🙈

    Thanks

  8. Pingback: cheap wigs

Comments are closed.

10 thoughts on “Firebase Phone Number Auth integration

  1. @Sparragus no one specifically. I’ll take a look at Android on Monday if theres no PR. IOS looks a bit too complicated for my object c skills

  2. I’ve been looking into this today. I’ll have to speak internally about how to actually implement this (more best practice). The aim of this lib is to try and replicate the web SDK, however I don’t think it’ll be possible here.

    1. On the Web docs there’s no need for steps 1-3.
    2. signInWithPhoneNumber takes a phoneNumber & appVerifier (where appVerifier is redundant on the device).
    3. The native SDKs (at least on Android) takes a verifyPhoneNumber. It can also do things like auto detection. The response of which, can be directly passed into signInWithCredential.

    @chrisbianca @Salakar How do you suggest dealing with the following workflow:

    After calling verifyPhoneNumber, we return a promise which would resolve on onVerificationCompleted (Instantly verified or auto detected). The issue is though, there’s an optional onCodeSent which would prompt the user to enter the code manually (as it’s not been detected automagically). How would that fit into the API?

    firebase.auth().verifyPhoneNumber('+441234567')
      .then((credential) => {}) // onVerificationCompleted
      .catch(() => {});

    That may potentially never get called, as it’s hit the onCodeSent block. We could add a method like verifyPhoneCode or something, but then how would the user know whether to use this or not.

  3. Hello, I successfully got it working for iOS. Unfortunately I don’t have the time for a PR but I will describe how I went on. First, the NativeModule (my module is called WHOFirebaseAuth here)

    //
    //  WHOFirebaseAuth.m
    //  WhoCaresAppNew
    //
    //  Created by Enes Kaya on 29.05.17.
    //  Copyright © 2017 Facebook. All rights reserved.
    //
    
    #import "WHOFirebaseAuth.h"
    #import <FirebaseAuth/FirebaseAuth.h>
    
    @implementation WHOFirebaseAuth
    
    RCT_EXPORT_MODULE();
    
    RCT_EXPORT_METHOD(verifyPhoneNumber:(NSString*) userInput
                      callback:(RCTResponseSenderBlock) callback)
    {
        [[FIRPhoneAuthProvider provider]
         verifyPhoneNumber: userInput
         completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
           
           NSLog(@"WHOFirebaseAuth: %%@", userInput);
           
          if (error) {
            callback(@[error.localizedDescription, @"ERROR"]);
            NSLog(@"WHOFirebaseAuth: %%@", error.localizedDescription);
          } else {
            // Sets the verficiationID in UserDefaults for later usage
            NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
            [defaults setObject:verificationID forKey:@"authVerificationID"];
            
            callback(@[[NSNull null], verificationID]);
          }
          
        }];
    }
    
    RCT_EXPORT_METHOD(getVerificationId:(RCTResponseSenderBlock)callback)
    {
      NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
      NSString *verificationID = [defaults stringForKey:@"authVerificationID"];
      callback(@[[NSNull null], verificationID]);
    }
    
    @end

    You call it like this in your RN project:

    const WHOFirebaseAuth = NativeModules.WHOFirebaseAuth
    ...
    static sendVerificationCodeTo(phoneNumber) {
       return new Promise((resolve, reject) => {
    	WHOFirebaseAuth.verifyPhoneNumber(
    		phoneNumber,
    		(error, verificationID) => {
    			if (!error) {
    				resolve({
    					error: null,
    					verificationID: verificationID
    				})
    			} else {
    				reject({
    					error,
    					verificationID: null
    				})
    			}
    		}
    	)
       })
    }
    ...
    

    After that, if it was successful, the user get’s the code sent via SMS. Then you can log in like so:

    	/**
       * Signs the user in with PhoneAuth credential.
       *
       * @param  {[type]} verificationID The verificationID returned by this.sendVerificationCodeTo
       * @param  {[type]} code           The code which was sent via SMS
       * @return {[type]}                firebase.Promise containing non-null firebase.User
       */
    	static signInWithPhoneAuth(verificationID, code) {
    		var credential = firebase.auth.PhoneAuthProvider.credential(
    			verificationID,
    			code
    		)
    
    		return firebase.auth().signInWithCredential(credential)
    	}

    So, basically it’s a mix between the native SDK and the JS SDK. Remember to install Firebase/Auth via CocoaPods in version >4.0.0.

    Hope that helps, for me it’s working perfectly.

  4. I was just about to post a version of myself.
    What I did slightly different was I used promises rather than callbacks

    RCT_EXPORT_METHOD(verifyPhone:(NSString *)userInput
                      resolver:(RCTPromiseResolveBlock)resolve
                      rejecter:(RCTPromiseRejectBlock)reject)
    {
      [[FIRPhoneAuthProvider provider]
       verifyPhoneNumber:userInput
       completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
          if (error) {
             reject(@"Error on Phone Verification", @"Phone can't be verified", error);
          }
          NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
          [defaults setObject:verificationID forKey:@"authVerificationID"];
          resolve(verificationID);
      }];
    }
    
  5. So, it’s a tad more difficult on Android than I thought 😅 Does anyone else have an Idea?

  6. I’m back in the country now, so should be able to pick back up on this over the next few days. I’ll try and pick up on the questions above that haven’t already been answered:

    @subugwriter Thanks for raising the linking issue. Auto-verify on Android has been a right pain to deal with in a cross platform manner. What I’m going to try and do is the following:

    1. Update the current signInWithPhoneNumber to link the phone credential automatically if the user is already signed in.

    2. Expose a new verifyPhoneNumber endpoint to the API which will expose the underlying API more explicitly, e.g. onCodeSent, onAutoVerified, etc, so that the user can do what they want should they need anything more custom.

    @javamonn Thanks for mentioning FirebaseUI. This is certainly an option, however by using FirebaseUI there are some limitations – namely, that it will import all the underlying Firebase modules regardless of whether they’re being used in the rest of the app or not. Also, React Native makes it so easy to build UIs, that it shouldn’t really be necessary. Hopefully when the above changes I’ve proposed are made, this will render FirebaseUI unnecessary. I’m also not sure how well the new multi app support would translate across between react-native-firebase and FirebaseUI

    @maraujop Sounds like you’ve not got the required Android libraries being imported correctly. I’d need the rest of the error message to be able to help any further than that.

    @faahmad I’d suggest you debug your verifyCode method and see whether you’re correctly setting confirmResult in your reducer.

    @bintoll Documentation will be firmed up once we’ve agreed on the final implementation. We wanted to find out how everybody was using the library and highlight the edge cases, e.g. linking the credential, before we spent too much time there.

  7. All,

    I’ve just pushed up the verifyPhoneNumber implementation (as @chrisbianca mentioned above). Source code.

    This implementation gives you full control of the phone number verification flow on either platform as well as a flexible api to suite any UI flow and should be familiar to use if you’ve used things like storage upload tasks / database on listeners.


    Cross Platform Example

    This code snippet covers all scenarios for both android and iOS, how you implement this is entirely up to you. A simpler iOS only usage example can be found below this example.

    firebase.auth()
      .verifyPhoneNumber('+441234567890')
      .on('state_changed', (phoneAuthSnapshot) => {
        // How you handle these state events is entirely up to your ui flow and whether
        // you need to support both ios and android. In short: not all of them need to
        // be handled - it's entirely up to you, your ui and supported platforms.
    
        // E.g you could handle android specific events only here, and let the rest fall back
        // to the optionalErrorCb or optionalCompleteCb functions
        switch (phoneAuthSnapshot.state) {
          // ------------------------
          //  IOS AND ANDROID EVENTS
          // ------------------------
          case firebase.auth.PhoneAuthState.CODE_SENT: // or 'sent'
            console.log('code sent');
            // on ios this is the final phone auth state event you'd receive
            // so you'd then ask for user input of the code and build a credential from it
            break;
          case firebase.auth.PhoneAuthState.ERROR: // or 'error'
            console.log('verification error');
            console.log(phoneAuthSnapshot.error);
            break;
    
          // ---------------------
          // ANDROID ONLY EVENTS
          // ---------------------
          case firebase.auth.PhoneAuthState.AUTO_VERIFY_TIMEOUT: // or 'timeout'
            console.log('auto verify on android timed out');
            // proceed with your manual code input flow, same as you would do in
            // CODE_SENT if you were on IOS
            break;
          case firebase.auth.PhoneAuthState.AUTO_VERIFIED: // or 'verified'
            // auto verified means the code has also been automatically confirmed as correct/received
            // phoneAuthSnapshot.code will contain the auto verified sms code - no need to ask the user for input.
            console.log('auto verified on android');
            console.log(phoneAuthSnapshot);
            // Example usage if handling here and not in optionalCompleteCb:
            // const { verificationId, code } = phoneAuthSnapshot;
            // const credential = firebase.auth.PhoneAuthProvider.credential(verificationId, code);
    
            // Do something with your new credential, e.g.:
            // firebase.auth().signInWithCredential(credential);
            // firebase.auth().linkWithCredential(credential);
            // etc ...
            break;
        }
      }, (error) => {
        // optionalErrorCb would be same logic as the ERROR case above,  if you've already handed
        // the ERROR case in the above observer then there's no need to handle it here
        console.log(error);
        // verificationId is attached to error if required
        console.log(error.verificationId);
      }, (phoneAuthSnapshot) => {
        // optionalCompleteCb would be same logic as the AUTO_VERIFIED/CODE_SENT switch cases above
        // depending on the platform. If you've already handled those cases in the observer then
        // there's absolutely no need to handle it here.
    
        // Platform specific logic:
        // - if this is on IOS then phoneAuthSnapshot.code will always be null
        // - if ANDROID auto verified the sms code then phoneAuthSnapshot.code will contain the verified sms code
        //   and there'd be no need to ask for user input of the code - proceed to credential creating logic
        // - if ANDROID auto verify timed out then phoneAuthSnapshot.code would be null, just like ios, you'd
        //   continue with user input logic.
        console.log(phoneAuthSnapshot);
      });
    // optionally also supports .then & .catch instead of optionalErrorCb &
    // optionalCompleteCb (with the same resulting args)

    Basic Example

    The api is flexible enough to not force those of you that only need to support one platform (in this case iOS) into a wall of code.

    Whilst this example makes use of the optional resulting promise, you can still however use the observer api instead and handle CODE_SENT and ERROR events individually like in the above detailed example – again it’s entirely up to you.

    firebase.auth()
      .verifyPhoneNumber('+441234567890')
      .then((phoneAuthSnapshot) => {
        console.log(phoneAuthSnapshot);
        // wait / get users code input then:
        // const { verificationId } = phoneAuthSnapshot;
        // const { codeInput } = this.state; // tied to your input box, for example
        // const credential = firebase.auth.PhoneAuthProvider.credential(verificationId, codeInput);
    
        // Do something with your new credential, e.g.:
        // firebase.auth().signInWithCredential(credential);
        // firebase.auth().linkWithCredential(credential);
      })
      .catch((error) => {
        console.log(error);
        console.log(error.verificationId);
      });

    As verifyPhoneNumber covers full support for the firebase phone auth api I think we close to closing this issue 🎉, just some further testing required by us internally and also any feedback you guys may have?

    As for signInWithPhoneNumber I think we’ll leave this in it’s current state (without auto linking) – even though verifyPhoneNumber negates the need for it – for those of you who’d prefer to use it (unless you tell us otherwise?).

    Thanks again all for helping us work through the implementation.

  8. @maraujop this has been pushed up for android, you should be good to go now for android – will sort ios shortly.

    My UI skills aren’t amazing, but here’s a gif of android working with auto verify included, it’s pretty quick:

    boop

  9. Hey all, this is now part of the full v3 release (with Cloud Firestore 🎉 ) that we pushed out to npm yesterday. I’ll be closing this issue now. I’m still working on the docs but for now please use this thread (#119 (comment) specifically) for implementation guides.

    Please raise any new issues in separate github issues going forward. If you have queries / or want to continue discussing this further you can join us on discord – this thread takes far too long to load now 🙈

    Thanks

Comments are closed.