Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firebase Phone Number Auth integration #119

Closed
jasan-s opened this issue May 18, 2017 · 137 comments
Closed

Firebase Phone Number Auth integration #119

jasan-s opened this issue May 18, 2017 · 137 comments

Comments

@jasan-s
Copy link

jasan-s commented May 18, 2017

Is the new Firebase Phone number Auth on the roadmap?

@Ehesp
Copy link
Member

Ehesp commented May 18, 2017

Yeah it will be. Will look at seeing what's possible to do

@Salakar
Copy link
Member

Salakar commented May 18, 2017

@jasan-s @Ehesp - might make sense to wait until android support is out for this at the end of may: https://firebase.google.com/docs/auth/android/phone-auth

@DavidKuennen
Copy link
Contributor

DavidKuennen commented May 18, 2017

They will support this? Awesome 😄

Since I currently use Facebook Account Kit to verify phone numbers, I actually consider waiting with my first release until I can use it with firebase.

@jeveloper
Copy link

I believe its already available as they have open sourced their SDKs

@Salakar
Copy link
Member

Salakar commented May 19, 2017

@jeveloper it's only available in ios at the moment

@jeveloper
Copy link

ohh thats odd, i thought they were just reusing fabrics digits which works on anything

thanks man!

@Froelund
Copy link

Froelund commented Jun 1, 2017

Maybe now is too early June :)

Phone number sign-in is coming soon to Firebase on Android. Check this page in early June 2017 for details.

@chrisbianca
Copy link
Contributor

Yesterday it said late May! :)

@perrosnk
Copy link

perrosnk commented Jun 1, 2017

+1 I am also really interested in this feature!

@willbattel
Copy link

+1 We're anxiously awaiting this feature after Google finishes implementation for Android

@Salakar Salakar added this to the v2 milestone Jun 7, 2017
@willbattel
Copy link

https://firebase.google.com/support/release-notes/android#20170607

Now available on Android SDK!

@Sparragus
Copy link
Contributor

Is anyone assigned or already working a PR to this issue? If not, I could try to do it myself.

@Ehesp
Copy link
Member

Ehesp commented Jun 8, 2017

@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

@Ehesp
Copy link
Member

Ehesp commented Jun 15, 2017

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.

@eneskaya
Copy link

eneskaya commented Jun 20, 2017

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.

@yash2code
Copy link

@eneskaya will it work on android with same syntax and all ?

@eneskaya
Copy link

@yash2code The JS part of the code yes, but obviously not the objective-c part. I will, later today implement the android side.

@Ehesp
Copy link
Member

Ehesp commented Jun 20, 2017

@eneskaya Any thought on my comment above regarding onCodeSent would be handy on Android.

@yash2code
Copy link

@eneskaya Ty sir, I m surely waiting for that !! :)

@eneskaya
Copy link

@Ehesp not yet, but will look into that. I'll keep you posted

@bennygenel
Copy link

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);
  }];
}

@eneskaya
Copy link

So, it's a tad more difficult on Android than I thought 😅 Does anyone else have an Idea?

@jesseditson
Copy link

Need this for a project, so I can pick up the work if someone's not already on it - @eneskaya, is your work all on this comment thread or is there a branch I should work from?

@javamonn
Copy link

javamonn commented Sep 13, 2017

For what it's worth, we recently got Firebase phone authentication working in a react-native project without needing to depend on the functionality being built into react-native-firebase.

FirebaseUI provides drop-in phone authentication interfaces for iOS and Android and is pretty easy to wrap to spawn it with a native-module call. It handles sending and confirming the SMS token. We then retrieve the authentication token to generate a custom token and eventually sign in to react-native-firebase with signInWithCustomToken, but I imagine if FirebaseUI and react-native-firebase share the same Firebase instance it would detect the authentication state change without any further integration.

Obviously FirebaseUI is not an option if your app needs a custom phone auth UI, but it's a good stop-gap until there's more robust support for the underlying APIs in react-native-firebase. I imagine the phone auth code in FirebaseUI might be useful to review for implementers here as well.

@jcharbo
Copy link

jcharbo commented Sep 13, 2017

@javamonn that sounds awesome. Can you provide some more info or maybe sample code on your integration?
thanks

@bintoll
Copy link

bintoll commented Sep 14, 2017

Hello! Could someone help me please i have an error: "Remote notification and background fetching need to be set up for the app. If app delegate swizzling is disabled, the APNs device token received by UIApplicationDelegate needs to be forwarded to FIRAuth's APNSToken property.". Do i need to set up firebase cloud messaging for auth with phone for firebase (do i need to make swizzling disabled or not?)? It is pointed that cloud messaging is optional in installation docs. Thanks
also could you tell me please what is "auto-verify" in this context?

@eneskaya
Copy link

eneskaya commented Sep 14, 2017 via email

@bintoll
Copy link

bintoll commented Sep 14, 2017

@eneskaya Thanks for fast answer, also could you tell me please is it possible to test it and debug this auth without generating APNs Auth Key (i do not have payed dev account now. So the question is can i test this method of auth without payed account? (how?)

@eneskaya
Copy link

eneskaya commented Sep 14, 2017 via email

@bintoll
Copy link

bintoll commented Sep 14, 2017

@eneskaya Thank you very mush! You helped me a lot. I kindly suggest firebase developers to add some information about phone auth in the doc. I know that it is only alpha, but anyway, just some words will be good.

@eneskaya
Copy link

eneskaya commented Sep 14, 2017 via email

@D1no
Copy link
Contributor

D1no commented Sep 14, 2017

@javamonn could you share the code you guys use to bridge and share firebaseUI? Offloading auth and all its checks sounds like viable idea.

@maraujop
Copy link

Ok I'm trying to setup react-native-firebase@next to try Phone authentication and followed the instructions here https://invertase.io/react-native-firebase/#/installation-android for v3.x.x

Everything compiles, but when I start the app, before seeing anything I'm getting this error

C++ exception in 'NativeModules':
java.lang.NoClassDefFoundError: com.google.firebase.auth.AuthCredential

captura de pantalla 2017-09-15 a las 13 25 38

Any hints what can be happening?

Thanks, cheers
Miguel

@chrisbianca
Copy link
Contributor

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.

@maraujop
Copy link

Thanks @chrisbianca for your answer.

It took me a while, but I finally found a cross dependency problem, another library was loading an older version of Firebase. It is now working good, as I've excluded dependencies from libraries and manually forced dependencies. This article was of great help.

Beware that I've had to do a little adjustment to your javascript example, to handle auto verification, when there is no need to request to the user for an SMS code.

Now, I'm trying to compile it correctly in iOS, but I'm facing this compile error:

Argument list too long: recursive header expansion failed at /Users/map/repos/paytween/node_modules/react-native-fcm/ios/../../../ios/Pods/React/node_modules/utf-8-validate/node_modules/nan/tools.

Maybe react-native-firebase is not compatible with react-native-fcm? I have been using that project for FCM, and I wouldn't like to change it all now, as I'm in a hurry to have this finished.

My guess is that this also has to do with inter dependecy problems, or maybe that react-native-fcm is not set up using Pods. Any hint would be greatly appreciated.

Thanks. By the way your project hierarchy and code quality is amazing, great work!

Cheers,
Miguel

@chrisbianca
Copy link
Contributor

@maraujop Not sure how compatible we are with react-native-fcm nowadays as I've not tested recently. In the past we have been, though obviously in the long term it would make sense to port over to the react-native-firebase which does offer messaging support and is something we will be focusing more attention on once phone auth is out of the way ;)

In terms of your error, I'd suggest clearing down your project, DerivedData, etc and restarting XCode. See if that helps...

@Salakar
Copy link
Member

Salakar commented Sep 24, 2017

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.

@maraujop
Copy link

Thanks @chrisbianca I finally managed to get it working. It was a bad iOS + cocoapods setup. Although it's true that search paths in react-native-fcm are too open and can cause trouble. Anyway, I finally got it working in both platforms. In the future, I will probably move into using one single app.

@Salakar i was trying to change my code to use this new verifyPhoneNumber flow. I believe that you forgot to push some native Android code.

Currently PhoneAuthListener calls native verifyPhoneNumber, which I haven't found anywhere.

this._auth._native.verifyPhoneNumber(

So, it ends up in this error:

captura de pantalla 2017-09-25 a las 13 11 38

@jcharbo
Copy link

jcharbo commented Sep 25, 2017

@maraujop I'm using fcm as well. Do you have any tips to share for getting it working?
thanks

@Salakar
Copy link
Member

Salakar commented Sep 25, 2017

@maraujop and others, I probably should of said this above but please wait until we give the go ahead before trying to use verifyPhoneNumber :)

As you correctly said the native parts are not there yet as they require a few more tweaks / testing.

My post was a heads up of what the new API is :)

@jcharbo
Copy link

jcharbo commented Sep 25, 2017

Thanks @Salakar , do you have an ETA?

@maraujop
Copy link

maraujop commented Sep 26, 2017

@Salakar Oh, I totally misunderstood your post, sorry, as you said you had merged the implementation I understood it was fully there.

@jcharbo Make sure your LIBRARY_SEARCH_PATHS looks like this:

LIBRARY_SEARCH_PATHS = (
	"\"$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)\"",
	"$(inherited)",
);

Also make sure that you do pod update in your ios folder. If you have any problem, let me know what it is.

@Salakar
Copy link
Member

Salakar commented Sep 30, 2017

@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

@Salakar
Copy link
Member

Salakar commented Oct 4, 2017

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

@Salakar Salakar closed this as completed Oct 4, 2017
@jcharbo
Copy link

jcharbo commented Oct 4, 2017

Hi everyone, I appreciate your work on this but does anyone have an estimate on when this will all be ready for production?

@Salakar
Copy link
Member

Salakar commented Oct 4, 2017

@jcharbo

image

@jcharbo
Copy link

jcharbo commented Oct 4, 2017

awesome @Salakar , thanks!

@invertase invertase locked and limited conversation to collaborators Oct 5, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests