简体   繁体   中英

Firebase Auth using phone number returns an internal error

I set up my app to be able to send Apple Notifications using firebase and I verified that it works using the console. Now I want to do phone authentication which is built on top of APN.

So I wrote this:

PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber) { verificationID, error in
  if error != nil {
    print("Verification code not sent \(error!)")
  } else {
    print ("Successful.")
  }

And I get:

Error Domain=FIRAuthErrorDomain Code=17999 "An internal error has occurred, print and inspect the error details for more information." UserInfo={NSUnderlyingError=0x170046db0 {Error Domain=FIRAuthInternalErrorDomain Code=3 "(null)" UserInfo={FIRAuthErrorUserInfoDeserializedResponseKey={
    code = 500;
    message = "<null>";
}}}, error_name=ERROR_INTERNAL_ERROR, NSLocalizedDescription=An internal error has occurred, print and inspect the error details for more information.}

Any idea? Should I file a bug against firebase?

I am using iOS SDK 4.0.0 (latest zip I could find.)

UPDATE:

I disabled method swizzling by adding FirebaseAppDelegateProxyEnabled to info.plist and set it to NO

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    // Pass device token to auth.
    Auth.auth().setAPNSToken(deviceToken, type: .prod)
}

Tested with latest Firebase iOS SDK ie 4.0.0 and Xcode 8.3

Firstly , remove this key FirebaseAppDelegateProxyEnabled from info.plist. This is not needed.

Now in AppDelegate.swift add following functions

import Firebase
import UserNotifications

@UIApplicationMain

class AppDelegate: UIResponder, UIApplicationDelegate , UNUserNotificationCenterDelegate{
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        if #available(iOS 10.0, *) {
            // For iOS 10 display notification (sent via APNS)
            UNUserNotificationCenter.current().delegate = self
            let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
            UNUserNotificationCenter.current().requestAuthorization(
                options: authOptions,
                completionHandler: {_, _ in })
        } else {
            let settings: UIUserNotificationSettings =
                UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
            application.registerUserNotificationSettings(settings)
        }

        application.registerForRemoteNotifications()
        FirebaseApp.configure()
        return true
    }
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    // Pass device token to auth.
    let firebaseAuth = Auth.auth()

    //At development time we use .sandbox
    firebaseAuth.setAPNSToken(deviceToken, type: AuthAPNSTokenType.sandbox)

    //At time of production it will be set to .prod
}

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    let firebaseAuth = Auth.auth()

    if (firebaseAuth.canHandleNotification(userInfo)){
        print(userInfo)
        return
    }
}*

Send a verification code to the user's phone:

In the class where you want to integrate Phone Authentication write :

Note : I have added +91 as its country code for India. You can add country code according to your region.

 PhoneAuthProvider.provider().verifyPhoneNumber("+919876543210") { (verificationID, error) in
       if ((error) != nil) {
             // Verification code not sent.
             print(error)
       } else {
              // Successful. User gets verification code 
              // Save verificationID in UserDefaults
             UserDefaults.standard.set(verificationID, forKey: "firebase_verification")
             UserDefaults.standard.synchronize()
             //And show the Screen to enter the Code.
       }               

Sign in the user with the verification code :

 let verificationID = UserDefaults.standard.value(forKey: "firebase_verification")
 let credential = PhoneAuthProvider.provider().credential(withVerificationID: verificationID! as! String, verificationCode: self.txtEmailID.text!)

   Auth.auth().signIn(with: credential, completion: {(_ user: User, _ error: Error?) -> Void in
         if error != nil {
            // Error
          }else {
             print("Phone number: \(user.phoneNumber)")
              var userInfo: Any? = user.providerData[0]
                    print(userInfo)
                }
         } as! AuthResultCallback)

In my case it was the apns token type that was wrong:

Auth.auth().setAPNSToken(deviceToken, type: AuthAPNSTokenType.prod)

should have been:

Auth.auth().setAPNSToken(deviceToken, type: AuthAPNSTokenType.sandbox)

Double check that the app bundle ID in Xcode matches the bundle ID in Firebase exactly . And by exactly , make sure their case matches - Xcode likes to use mixed case by default for the app name part of the bundle ID.

If you end up changing the bundle ID in Xcode, make sure to manually delete the provisioning profile for the app before generating a new one in Xcode, or it will repeatedly fail (Apple apparently ignores case on profile names).

Well, in my case I have sending wrong self.verificationID to FIRAuthCredential . If you are having this error, then please print your verificationID and check, is that the same one you are sending to FIRAuthCredential .

Here is my code in objC :

[[FIRPhoneAuthProvider provider] verifyPhoneNumber:self.phoneNumberTextField.text
                                            UIDelegate:nil
                                            completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
                                                if (error) {
                                                    NSLog(@"error %@", error.localizedDescription);
                                                    return;
                                                }
                                                NSLog(@"verificationID %@", verificationID);
                                                self.verificationID = [NSString stringWithFormat:@"%@", verificationID];

//                                                NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
//                                                [defaults setObject:verificationID forKey:@"authVerificationID"];
//                                                NSString *verificationID = [defaults stringForKey:@"authVerificationID"];

                                                // Sign in using the verificationID and the code sent to the user
                                                // ...
                                            }];

I accidentally send wrong verificationID here :

self.verificationID = [NSString stringWithFormat:@"verificationID",];

Right one is this :

self.verificationID = [NSString stringWithFormat:@"%@", verificationID];

And then I send it to FIRAuthCredential like this :

FIRAuthCredential *credential = [[FIRPhoneAuthProvider provider]
                                     credentialWithVerificationID:self.verificationID
                                     verificationCode:self.pinCodeTextField.text];

    [[FIRAuth auth] signInWithCredential:credential
                              completion:^(FIRUser *user, NSError *error) {
                                  if (error) {
                                      NSLog(@"error %@", error);
                                      return;
                                  }
                                  NSLog(@"Success");
                                  // User successfully signed in. Get user data from the FIRUser object
                                  // ...
                              }];

Which return success successfully. Hope it will help to others.

i am solve it easy make type .sandbox

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    // Pass device token to auth.
    let firebaseAuth = Auth.auth()
    //At development time we use .sandbox
    firebaseAuth.setAPNSToken(deviceToken, type: AuthAPNSTokenType.sandbox)
}

and remove this line from code

Auth.auth().settings.isAppVerificationDisabledForTesting = TRUE

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM