Authenticate with Firebase on iOS using a Phone Number

You can use Firebase Authentication to sign in a user by sending an SMS message to the user's phone. The user signs in using a one-time code contained in the SMS message.

The easiest way to add phone number sign-in to your app is to use FirebaseUI, which includes a drop-in sign-in widget that implements sign-in flows for phone number sign-in, as well as password-based and federated sign-in. This document describes how to implement a phone number sign-in flow using the Firebase SDK.

Before you begin

  1. Add Firebase to your iOS project.
  2. Include the following pods in your Podfile:
    pod 'Firebase/Auth'
    
  3. If you haven't yet connected your app to your Firebase project, do so from the Firebase console.

Security concerns

Authentication using only a phone number, while convenient, is less secure than the other available methods, because possession of a phone number can be easily transferred between users. Also, on devices with multiple user profiles, any user that can receive SMS messages can sign in to an account using the device's phone number.

If you use phone number based sign-in in your app, you should offer it alongside more secure sign-in methods, and inform users of the security tradeoffs of using phone number sign-in.

Enable Phone Number sign-in for your Firebase project

To sign in users by SMS, you must first enable the Phone Number sign-in method for your Firebase project:

  1. In the Firebase console, open the Authentication section.
  2. On the Sign-in Method page, enable the Phone Number sign-in method.

Firebase's phone number sign-in request quota is high enough that most apps won't be affected. However, if you need to sign in a very high volume of users with phone authentication, you might need to upgrade your pricing plan. See the pricing page.

Enable app verification

To use phone number authentication, Firebase must be able to verify that phone number sign-in requests are coming from your app. There are two ways Firebase Authentication accomplishes this:

  • Silent APNs notifications: When you sign in a user with their phone number for the first time on a device, Firebase Authentication sends a token to the device using a silent push notification. If your app successfully receives the notification from Firebase, phone number sign-in can proceed.

    For iOS 8.0 and newer, silent notifications do not require explicit user consent and is therefore unaffected by a user declining to receive APNs notifications in the app. Thus, the app does not need to request user permission to receive push notifications when implementing Firebase phone number auth.

  • reCAPTCHA verification: In the event that sending or receiving a silent push notification is not possible, such as when the user has disabled background refresh for your app, or when testing your app on an iOS simulator, Firebase Authentication uses reCAPTCHA verification to complete the phone sign-in flow. The reCAPTCHA challenge can often be completed without the user having to solve anything.

When silent push notifications are properly configured, only a very small percentage of users will experience the reCAPTCHA flow. Nonetheless, you should ensure that phone number sign-in functions correctly whether or not silent push notifications are available.

Start receiving silent notifications

To enable APNs notifications for use with Firebase Authentication:

  1. In Xcode, enable push notifications for your project.
  2. Upload your APNs authentication key to Firebase. If you don't already have an APNs authentication key, see Configuring APNs with FCM.

    1. Inside your project in the Firebase console, select the gear icon, select Project Settings, and then select the Cloud Messaging tab.

    2. In APNs authentication key under iOS app configuration, click the Upload button.

    3. Browse to the location where you saved your key, select it, and click Open. Add the key ID for the key (available in Certificates, Identifiers & Profiles in the Apple Developer Member Center) and click Upload.

    If you already have an APNs certificate, you can upload the certificate instead.

Set up reCAPTCHA verification

To enable the Firebase SDK to use reCAPTCHA verification:

  1. Add custom URL schemes to your Xcode project:
    1. Open your project configuration: double-click the project name in the left tree view. Select your app from the TARGETS section, then select the Info tab, and expand the URL Types section.
    2. Click the + button, and add a URL scheme for your reversed client ID. To find this value, open the GoogleService-Info.plist configuration file, and look for the REVERSED_CLIENT_ID key. Copy the value of that key, and paste it into the URL Schemes box on the configuration page. Leave the other fields blank.

      When completed, your config should look something similar to the following (but with your application-specific values):

  2. Optional: If you want to customize the way your app presents the SFSafariViewController or UIWebView when displaying the reCAPTCHA to the user, create a custom class that conforms to the FIRAuthUIDelegate protocol, and pass it to verifyPhoneNumber:UIDelegate:completion:.

Send a verification code to the user's phone

To initiate phone number sign-in, present the user an interface that prompts them to provide their phone number, and then call verifyPhoneNumber:UIDelegate:completion: to request that Firebase send an authentication code to the user's phone by SMS:

  1. Get the user's phone number.

    Legal requirements vary, but as a best practice and to set expectations for your users, you should inform them that if they use phone sign-in, they might receive an SMS message for verification and standard rates apply.

  2. Call verifyPhoneNumber:UIDelegate:completion:, passing to it the user's phone number.

    Swift

    PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber, uiDelegate: nil) { (verificationID, error) in
      if let error = error {
        self.showMessagePrompt(error.localizedDescription)
        return
      }
      // Sign in using the verificationID and the code sent to the user
      // ...
    }

    Objective-C

    [[FIRPhoneAuthProvider provider] verifyPhoneNumber:userInput
                                            UIDelegate:nil
                                            completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) {
      if (error) {
        [self showMessagePrompt:error.localizedDescription];
        return;
      }
      // Sign in using the verificationID and the code sent to the user
      // ...
    }];

    When you call verifyPhoneNumber:UIDelegate:completion:, Firebase sends a silent push notification to your app, or issues a reCAPTCHA challenge to the user. After your app receives the notification or the user completes the reCAPTCHA challenge, Firebase sends an SMS message containing an authentication code to the specified phone number and passes a verification ID to your completion function. You will need both the verification code and the verification ID to sign in the user.

    The SMS message sent by Firebase can also be localized by specifying the auth language via the languageCode property on your Auth instance.

    Swift

     // Change language code to french.
     Auth.auth().languageCode = "fr";
    

    Objective-C

     // Change language code to french.
     [FIRAuth auth].languageCode = @"fr";
    
  3. Save the verification ID and restore it when your app loads. By doing so, you can ensure that you still have a valid verification ID if your app is terminated before the user completes the sign-in flow (for example, while switching to the SMS app).

    You can persist the verification ID any way you want. A simple way is to save the verification ID with the NSUserDefaults object:

    Swift

    UserDefaults.standard.set(verificationID, forKey: "authVerificationID")
    

    Objective-C

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

    Then, you can restore the saved value:

    Swift

    let verificationID = UserDefaults.standard.string(forKey: "authVerificationID")
    

    Objective-C

    NSString *verificationID = [defaults stringForKey:@"authVerificationID"];
    

If the call to verifyPhoneNumber:UIDelegate:completion: succeeds, you can prompt the user to type the verification code when they receive it in the SMS message.

Sign in the user with the verification code

After the user provides your app with the verification code from the SMS message, sign the user in by creating a FIRPhoneAuthCredential object from the verification code and verification ID and passing that object to signInWithCredential:completion:.

  1. Get the verification code from the user.
  2. Create a FIRPhoneAuthCredential object from the verification code and verification ID.

    Swift

    let credential = PhoneAuthProvider.provider().credential(
        withVerificationID: verificationID,
        verificationCode: verificationCode)

    Objective-C

    FIRAuthCredential *credential = [[FIRPhoneAuthProvider provider]
        credentialWithVerificationID:verificationID
                    verificationCode:userInput];
  3. Sign in the user with the FIRPhoneAuthCredential object:

    Swift

    Auth.auth().signIn(with: credential) { (user, error) in
      if let error = error {
        // ...
        return
      }
      // User is signed in
      // ...
    }
    }

    Objective-C

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

Appendix: Using phone sign-in without swizzling

Firebase Authentication uses method swizzling to automatically obtain your app's APNs token, to handle the silent push notifications that Firebase sends to your app, and to automatically intercept the custom scheme redirect from the reCAPTCHA verification page during verification.

If you prefer not to use swizzling, you can disable it by adding the flag FirebaseAppDelegateProxyEnabled to your app's Info.plist file and setting it to NO. Note that setting this flag to NO also disables swizzling for other Firebase products, including Firebase Cloud Messaging.

If you disable swizzling, you must explicitly pass the APNs device token, push notifications, and the custom scheme redirect URL to Firebase Authentication.

To obtain the APNs device token, implement the application:didRegisterForRemoteNotificationsWithDeviceToken: method, and in it, pass the device token to FIRAuth's setAPNSToken:type: method.

Swift

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

  // Further handling of the device token if needed by the app
  // ...
}

Objective-C

- (void)application:(UIApplication *)application
    didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  // Pass device token to auth.
  [[FIRAuth auth] setAPNSToken:deviceToken type:FIRAuthAPNSTokenTypeProd];
  // Further handling of the device token if needed by the app.
}

To handle push notifications, in the application:didReceiveRemoteNotification:fetchCompletionHandler: method, check for Firebase auth related notifications by calling FIRAuth's canHandleNotification: method.

Swift

func application(_ application: UIApplication,
    didReceiveRemoteNotification notification: [AnyHashable : Any],
    fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
  if Auth.auth().canHandleNotification(notification) {
    completionHandler(UIBackgroundFetchResultNoData)
    return
  }
  // This notification is not auth related, developer should handle it.
}

Objective-C

- (void)application:(UIApplication *)application
    didReceiveRemoteNotification:(NSDictionary *)notification
          fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  // Pass notification to auth and check if they can handle it.
  if ([[FIRAuth auth] canHandleNotification:notification]) {
    completionHandler(UIBackgroundFetchResultNoData);
    return;
  }
  // This notification is not auth related, developer should handle it.
}

To handle the custom scheme redirect URL, implement the application:openURL:sourceApplication:annotation: method for devices running iOS 8 and older, and the application:openURL:options: method for devices running iOS 9 and newer, and in them, pass the URL to FIRAuth's canHandleURL method.

Swift

// For iOS 9+
func application(_ application: UIApplication, open url: URL,
    options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
  if Auth.auth().canHandle(url) {
    return true
  }
  // URL not auth related, developer should handle it.
}

// For iOS 8-
func application(_ application: UIApplication,
                 open url: URL,
                 sourceApplication: String?,
                 annotation: Any) -> Bool {
  if Auth.auth().canHandle(url) {
    Return true
  }
  // URL not auth related, developer should handle it.
}

Objective-C

// For iOS 9+
- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
  if ([[FIRAuth auth] canHandleURL:url]) {
    return YES;
  }
  // URL not auth related, developer should handle it.
}

// For iOS 8-
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
  if ([[FIRAuth auth] canHandleURL:url]) {
    return YES;
  }
  // URL not auth related, developer should handle it.
}

Next steps

After a user signs in for the first time, a new user account is created and linked to the credentials—that is, the user name and password, phone number, or auth provider information—the user signed in with. This new account is stored as part of your Firebase project, and can be used to identify a user across every app in your project, regardless of how the user signs in.

  • In your apps, you can get the user's basic profile information from the FIRUser object. See Manage Users.

  • In your Firebase Realtime Database and Cloud Storage Security Rules, you can get the signed-in user's unique user ID from the auth variable, and use it to control what data a user can access.

You can allow users to sign in to your app using multiple authentication providers by linking auth provider credentials to an existing user account.

To sign out a user, call signOut:.

Swift

    let firebaseAuth = Auth.auth()
do {
  try firebaseAuth.signOut()
} catch let signOutError as NSError {
  print ("Error signing out: %@", signOutError)
}
  

Objective-C

    NSError *signOutError;
BOOL status = [[FIRAuth auth] signOut:&signOutError];
if (!status) {
  NSLog(@"Error signing out: %@", signOutError);
  return;
}

You may also want to add error handling code for the full range of authentication errors. See Handle Errors.

Send feedback about...

Need help? Visit our support page.