# FirebaseUI for iOS — Auth FirebaseUI is an open-source library for iOS that provides simple, customizable UI bindings on top of [Firebase](https://firebase.google.com) SDKs to eliminate boilerplate code and promote best practices. FirebaseUI provides a drop-in auth solution that handles the UI flows for signing in users with email addresses and passwords, and federated identity providers such as Google Sign-In and Facebook Login. It is built on top of [Firebase Auth](https://firebase.google.com/docs/auth). The FirebaseUI Auth component implement best practices for authentication on mobile devices and websites, which can maximize sign-in and sign-up conversion for your app. It also handles edge cases like account recovery and account linking that can be security sensitive and error-prone to handle correctly. FirebaseUI can be easily customized to fit in with the rest of your app's visual style, and it is open source, so you aren't constrained in realizing the user experience you want. Compatible FirebaseUI Auth clients are also available for [Android](https://github.com/firebase/firebaseui-android/tree/main/auth) and [Web](https://github.com/firebase/firebaseui-web/). ## Table of Contents 1. [Installation](#installation) 1. [Usage instructions](#using-firebaseui-for-authentication) 1. [Customization](#customizing-firebaseui-for-authentication) ## Installation ### Importing FirebaseUI components for auth Add the following to your `Podfile`: ```ruby pod 'FirebaseUI/Auth' pod 'FirebaseUI/Email' pod 'FirebaseUI/Google' pod 'FirebaseUI/Facebook' pod 'FirebaseUI/Phone' pod 'FirebaseUI/OAuth' ``` ### Configuring sign-in providers To use FirebaseUI to authenticate users you first need to configure each provider you want to use in their own developer app settings. Please read the *Before you begin* section of the Firebase Auth guides at the following links: - [Email and password](https://firebase.google.com/docs/auth/ios/password-auth#before_you_begin) - [Google](https://firebase.google.com/docs/auth/ios/google-signin#before_you_begin) - [Facebook](https://firebase.google.com/docs/auth/ios/facebook-login#before_you_begin) - [Phone](https://firebase.google.com/docs/auth/ios/phone-auth#before_you_begin) - [Sign in with Apple](https://firebase.google.com/docs/auth/ios/apple#before_you_begin) - For Sign in with Apple, read the [Comply with Apple anonymized data requirements](https://firebase.google.com/docs/auth/ios/apple#comply-with-apple-anonymized-data-requirements) section as well. ## Using FirebaseUI for Authentication ### Configuration All operations, callbacks, UI customizations are done through an `FUIAuth` instance. The `FUIAuth` instance associated with the default Firebase Auth instance can be accessed as follows: ```swift // Swift import FirebaseAuthUI /* ... */ FirebaseApp.configure() let authUI = FUIAuth.defaultAuthUI() // You need to adopt a FUIAuthDelegate protocol to receive callback authUI?.delegate = self ``` ```objective-c // Objective-C @import FirebaseAuthUI; /* ... */ [FIRApp configure]; FUIAuth *authUI = [FUIAuth defaultAuthUI]; // You need to adopt a FUIAuthDelegate protocol to receive callback authUI.delegate = self; ``` This instance can then be configured with the providers you wish to support: ```swift // Swift import FirebaseAuthUI /* ... */ let providers: [FUIAuthProvider] = [ FUIEmailAuth(), FUIGoogleAuth(), FUIFacebookAuth(), FUIPhoneAuth(authUI: FUIAuth.defaultAuthUI()), FUIOAuth.appleAuthProvider(), FUIOAuth.twitterAuthProvider(), FUIOAuth.githubAuthProvider(), FUIOAuth.microsoftAuthProvider(), FUIOAuth.yahooAuthProvider(), ] authUI?.providers = providers ``` ```objective-c // Objective-C @import FirebaseAuthUI; /* ... */ NSArray> *providers = @[ [[FUIEmailAuth alloc] init], [[FUIGoogleAuth alloc] init], [[FUIFacebookAuth alloc] init], [[FUIPhoneAuth alloc] initWithAuthUI:[FUIAuth defaultAuthUI]], [FUIOAuth appleAuthProvider], [FUIOAuth twitterAuthProvider], [FUIOAuth githubAuthProvider], [FUIOAuth microsoftAuthProvider], [FUIOAuth yahooAuthProvider] ]; self.authUI.providers = providers; ``` For Google Sign-in support, add custom URL schemes to your Xcode project (step 1 of the [implement Google Sign-In documentation](https://developers.google.com/firebase/docs/auth/ios/google-signin#2_implement_google_sign-in)). For Sign in with Apple support, add the Sign in with Apple capability to your entitlements file. For Facebook Login support, follow step 3 and 4 of [Facebook login documentation](https://developers.google.com/firebase/docs/auth/ios/facebook-login#before_you_begin), and follow the [Facebook SDK for iOS Getting started documentation](https://developers.facebook.com/docs/ios/getting-started). Finally, add a call to handle the URL that your application receives at the end of the Google/Facebook authentication process. ```swift // Swift func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool { let sourceApplication = options[UIApplicationOpenURLOptionsKey.sourceApplication] as! String? if FUIAuth.defaultAuthUI()?.handleOpen(url, sourceApplication: sourceApplication) ?? false { return true } // other URL handling goes here. return false } ``` ```objective-c // Objective-C - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary *)options { NSString *sourceApplication = options[UIApplicationOpenURLOptionsSourceApplicationKey]; return [[FUIAuth defaultAuthUI] handleOpenURL:url sourceApplication:sourceApplication]; } ``` ### Sign In To start the authentication flow, obtain an `authViewController` instance from `FUIAuth`. In order to leverage FirebaseUI for iOS you must display the `authViewController`; you can present it as the first view controller of your app or present it from another view controller within your app. In order to present the `authViewController` obtain as instance as follows: ```swift // Swift // Present the auth view controller and then implement the sign in callback. let authViewController = authUI!.authViewController() func authUI(_ authUI: FUIAuth, didSignInWithAuthDataResult authDataResult: AuthDataResult?, error: Error?) { // handle user (`authDataResult.user`) and error as necessary } ``` ```objective-c // Objective-C UINavigationController *authViewController = [authUI authViewController]; // Use authViewController as your root view controller, // or present it on top of an existing view controller. - (void)authUI:(FUIAuth *)authUI didSignInWithAuthDataResult:(nullable FIRAuthDataResult *)authDataResult error:(nullable NSError *)error { // Implement this method to handle signed in user (`authDataResult.user`) or error if any. } ``` ### Configuring Email Link Sign In To use email link sign in, you will first need to enable it in the Firebase Console. Additionally, you will also have to enable Firebase Dynamic Links. You can enable email link sign in by initializing an `FUIEmailAuth` instance with `FIREmailLinkAuthSignInMethod`. You will also need to provide a valid `FIRActionCodeSettings` object with `handleCodeInApp` set to true. Additionally, you need to allowlist the URL you pass to the initializer; you can do so in the Firebase Console (Authentication -> Sign in Methods -> Authorized domains). ```objective-c // Objective-C FIRActionCodeSettings *actionCodeSettings = [[FIRActionCodeSettings alloc] init]; actionCodeSettings.URL = [NSURL URLWithString:@"https://example.appspot.com"]; actionCodeSettings.handleCodeInApp = YES; [actionCodeSettings setAndroidPackageName:@"com.firebase.example" installIfNotAvailable:NO minimumVersion:@"12"]; ``` ```swift // Swift var actionCodeSettings = ActionCodeSettings() actionCodeSettings.url = URL(string: "https://example.appspot.com") actionCodeSettings.handleCodeInApp = true actionCodeSettings.setAndroidPackageName("com.firebase.example", installIfNotAvailable: false, minimumVersion: "12") ``` Once you catch the deep link, you will need to pass it to the auth UI so it can be handled. ```objective-c // Objective-C [FUIAuth.defaultAuthUI handleOpenURL:url sourceApplication:sourceApplication]; ``` ```swift // Swift Auth.defaultAuthUI.handleOpenURL(url, sourceApplication: sourceApplication) ``` We support cross device email link sign in for the normal flows. It is not supported with anonymous user upgrade. By default, cross device support is enabled. You can disable it setting `forceSameDevice` to false in the `FUIEmailAuth` initializer. ## Customizing FirebaseUI for authentication ### Custom Terms of Service (ToS) and privacy policy URLs The Terms of Service URL for your application, which is displayed on the email/password account creation screen, can be specified as follows: ```swift // Swift let kFirebaseTermsOfService = URL(string: "https://firebase.google.com/terms/")! authUI?.tosurl = kFirebaseTermsOfService ``` ```objective-c // Objective-C authUI.TOSURL = [NSURL URLWithString:@"https://example.com/tos"]; ``` The same applies to the URL of your privacy policy: ```swift // Swift let kFirebasePrivacyPolicy = URL(string: "https://policies.google.com/privacy")! authUI?.privacyPolicyURL = kFirebasePrivacyPolicy ``` ### Custom strings You can override the default messages and prompts shown to your users. This can be useful for things such as adding support for languages other than English. In order to do so: ```swift // Swift authUI?.customStringsBundle = NSBundle.mainBundle() // Or any custom bundle. ``` ```objective-c // Objective-C authUI.customStringsBundle = [NSBundle mainBundle]; // Or any custom bundle. ``` The bundle should include [.strings](https://github.com/firebase/FirebaseUI-iOS/blob/main/FirebaseAuthUI/Strings/en.lproj/FirebaseAuthUI.strings) files that have the same names as the default files, namely `FirebaseAuthUI`, `FirebaseGoogleAuthUI`, and `FirebaseFacebookAuthUI`. Each string in these files should have the same key as its counterpart in the default `.strings` files. ### Custom sign-in screen You can customize everything about the authentication method picker screen, except for the actual sign-in buttons and their position. In order to do so, create a subclass of `FUIAuthPickerViewController` and customize it to your needs. Provide `FUIAuth` with an instance of your subclass by implementing the delegate method `authPickerViewControllerForAuthUI:` as follows: ```swift // Swift func authPickerViewController(for authUI: FUIAuth) -> FUIAuthPickerViewController { return CustomAuthPickerViewController(authUI: authUI) } ``` ```objective-c // Objective-C - (FUIAuthPickerViewController *)authPickerViewControllerForAuthUI:(FUIAuth *)authUI { return [[CustomAuthPickerViewController alloc] initWithAuthUI:authUI]; } ``` ### Custom email/password screens You can customize all email/password screens, including but not limited to: - Hiding the top `UINavigationBar` - Adding a `Cancel` button - Use a UI view other than `UITableView` Things that are not customizable: - `UIAlertController` popups (showing error labels instead) - Modifying the screen flow (combining screens or skipping particular screens) - Disabling validation, including email validation To customize the email/password screens, create a subclass of appropriate controller and implement it to your needs. Then set up `FUIAuth` with an instance of your subclass by implementing the following delegate methods: ```swift // Swift func emailEntryViewController(for authUI: FUIAuth) -> FUIEmailEntryViewController { return CustomEmailEntryViewController(authUI: authUI) } func passwordSignInViewController(for authUI: FUIAuth, email: String) -> FUIPasswordSignInViewController { return CustomPasswordSignInViewController(authUI: authUI, email: email) } func passwordSignUpViewController(for authUI: FUIAuth, email: String) -> FUIPasswordSignUpViewController { return CustomPasswordSignUpViewController(authUI: authUI, email: email) } func passwordRecoveryViewController(for authUI: FUIAuth, email: String) -> FUIPasswordRecoveryViewController { return CustomPasswordRecoveryViewController(authUI: authUI, email: email) } func passwordVerificationViewController(for authUI: FUIAuth, email: String, newCredential: AuthCredential) -> FUIPasswordVerificationViewController { return CustomPasswordVerificationViewController(authUI: authUI, email: email, newCredential: newCredential) } ``` ```objective-c // Objective-C - (FUIEmailEntryViewController *)emailEntryViewControllerForAuthUI:(FUIAuth *)authUI { return [[CustomEmailEntryViewController alloc] initWithAuthUI:authUI]; } - (FUIPasswordSignInViewController *)passwordSignInViewControllerForAuthUI:(FUIAuth *)authUI email:(NSString *)email { return [[CustomPasswordSignInViewController alloc] initWithAuthUI:authUI email:email]; } - (FUIPasswordSignUpViewController *)passwordSignUpViewControllerForAuthUI:(FUIAuth *)authUI email:(NSString *)email { return [[CustomPasswordSignUpViewController alloc] initWithAuthUI:authUI email:email]; } - (FUIPasswordRecoveryViewController *)passwordRecoveryViewControllerForAuthUI:(FUIAuth *)authUI email:(NSString *)email { return [[CustomPasswordRecoveryViewController alloc] initWithAuthUI:authUI email:email]; } - (FUIPasswordVerificationViewController *)passwordVerificationViewControllerForAuthUI:(FUIAuth *)authUI email:(NSString *)email newCredential:(FIRAuthCredential *)newCredential { return [[CustomPasswordVerificationViewController alloc] initWithAuthUI:authUI email:email newCredential:newCredential]; } ``` In your custom view controllers, call the same FirebaseUI methods as their parent classes. For example: - `- (void)onNext:(NSString *)textFieldValue; // Or any action that leads to the next screen` - `- (void)didChangeTextField:(NSString *)textFieldValue; // Usually called in viewWillAppear and after modification of text entry field` - `- (void)onBack;` - `- (void)cancelAuthorization;` Refer to the Objective-C and Swift samples for examples of how you can customize these views. ## Handling auto-upgrade of anonymous users By default, the auto-upgrade of anonymous users is disabled. You can enable it by simply changing the associated attribute of your Firebase Auth instance: ```swift authUI?.shouldAutoUpgradeAnonymousUsers = true ``` Enabling auto-upgrade of anonymous users increases the complexity of your auth flow by adding several more edge cases that need to be handled. As opposed to normal auth, which only involves one step, auto-upgrade presents three steps with four possibilities total: - At app launch, anonymously authenticate the user. User state can be accumulated on the anonymous user and linked to the non-anonymous account later. - At some point in your app, present the auth flow and authenticate the user using a non-anonymous auth method. - Following a successful auth attempt, if the user signs in to a new account, the anonymous account and the new account can be linked together without issue. - Otherwise, if logging into an existing user, FirebaseUI will return a merge conflict error containing the resulting `FIRAuthDataResult` corresponding to the existing account. This value should be used to login to the existing account without linking to the anonymous user, as the two accounts may have conflicting state (the anonymous account state will be discarded). ```swift func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) { if let error = error as NSError?, error.code == FUIAuthErrorCode.mergeConflict.rawValue { // Merge conflict error, discard the anonymous user and login as the existing // non-anonymous user. guard let credential = error.userInfo[FUIAuthCredentialKey] as? AuthCredential else { print("Received merge conflict error without auth credential!") return } Auth.auth().signInAndRetrieveData(with: credential) { (dataResult, error) in if let error = error as NSError? { print("Failed to re-login: \(error)") return } // Handle successful login } } else if let error = error { // Some non-merge conflict error happened. print("Failed to log in: \(error)") return } // Handle successful login } ```