You can let your users authenticate with Firebase using their Google Accounts by integrating Google Sign-In into your app.
Before you begin
- Add Firebase to your iOS project. Include the
following pods in your
Podfile
:pod 'Firebase/Auth' pod 'GoogleSignIn'
- If you haven't yet connected your app to your Firebase project, do so from the Firebase console.
- Enable Google Sign-In in the Firebase console:
- In the Firebase console, open the Auth section.
- On the Sign in method tab, enable the Google sign-in method and click Save.
1. Import the required header files
First, you must import the Firebase SDK and Google Sign-In SDK header files into your app.
Swift
In your app delegate, import the following header files:
import Firebase import GoogleSignIn
In the view controller of your sign-in view, import the following header files:
import Firebase import GoogleSignIn
Objective-C
In your app delegate, import the following header files:
@import Firebase; @import GoogleSignIn;
In the view controller of your sign-in view, import the following header files:
@import Firebase; @import GoogleSignIn;
2. Implement Google Sign-In
Implement Google Sign-In by following these steps. See the Google Sign-In developer documentation for details on using Google Sign-In with iOS.
- Add custom URL schemes to your Xcode project:
- 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.
- Click the + button, and add a URL scheme for your reversed
client ID. To find this value, open the
configuration file, and look for theGoogleService-Info.plist 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):
- Declare that the app delegate implements the
GIDSignInDelegate
protocol.Swift
InAppDelegate.swift
:class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
Objective-C
InAppDelegate.h
:@interface AppDelegate : UIResponder<UIApplicationDelegate, GIDSignInDelegate>
- In your app delegate's
application:didFinishLaunchingWithOptions:
method, configure theFirebaseApp
object and set the sign-in delegate.Swift
// Use Firebase library to configure APIs FirebaseApp.configure() GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID GIDSignIn.sharedInstance().delegate = self
Objective-C
// Use Firebase library to configure APIs [FIRApp configure]; [GIDSignIn sharedInstance].clientID = [FIRApp defaultApp].options.clientID; [GIDSignIn sharedInstance].delegate = self;
- Implement the
application:openURL:options:
method of your app delegate. The method should call thehandleURL
method of theGIDSignIn
instance, which will properly handle the URL that your application receives at the end of the authentication process.Swift
@available(iOS 9.0, *) func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool { return GIDSignIn.sharedInstance().handle(url) }
Objective-C
- (BOOL)application:(nonnull UIApplication *)application openURL:(nonnull NSURL *)url options:(nonnull NSDictionary<NSString *, id> *)options { return [[GIDSignIn sharedInstance] handleURL:url]; }
For your app to run on iOS 8 and older, also implement the deprecated
application:openURL:sourceApplication:annotation:
method.Swift
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool { return GIDSignIn.sharedInstance().handle(url) }
Objective-C
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { return [[GIDSignIn sharedInstance] handleURL:url]; }
- In the app delegate, implement the
GIDSignInDelegate
protocol to handle the sign-in process by defining the following methods:Objective-C
- (void)signIn:(GIDSignIn *)signIn didSignInForUser:(GIDGoogleUser *)user withError:(NSError *)error { // ... if (error == nil) { GIDAuthentication *authentication = user.authentication; FIRAuthCredential *credential = [FIRGoogleAuthProvider credentialWithIDToken:authentication.idToken accessToken:authentication.accessToken]; // ... } else { // ... } } - (void)signIn:(GIDSignIn *)signIn didDisconnectWithUser:(GIDGoogleUser *)user withError:(NSError *)error { // Perform any operations when the user disconnects from app here. // ... }
Swift
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) { // ... if let error = error { // ... return } guard let authentication = user.authentication else { return } let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken, accessToken: authentication.accessToken) // ... } func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) { // Perform any operations when the user disconnects from app here. // ... }
- In the view controller, override the
viewDidLoad
method to set the presenting view controller of theGIDSignIn
object, and (optionally) to sign in silently when possible.Objective-C
[GIDSignIn sharedInstance].presentingViewController = self; [[GIDSignIn sharedInstance] signIn];
Swift
GIDSignIn.sharedInstance()?.presentingViewController = self GIDSignIn.sharedInstance().signIn()
- Add a
GIDSignInButton
to your storyboard, XIB file, or instantiate it programmatically. To add the button to your storyboard or XIB file, add a View and set its custom class toGIDSignInButton
. - Optional: If you want to customize the button, do the
following:
Swift
- In your view controller, declare the sign-in button as a property.
@IBOutlet weak var signInButton: GIDSignInButton!
- Connect the button to the
signInButton
property you just declared. - Customize the button by setting the properties of the GIDSignInButton object.
Objective-C
- In your view controller's header file, declare the sign-in button as a
property.
@property(weak, nonatomic) IBOutlet GIDSignInButton *signInButton;
- Connect the button to the
signInButton
property you just declared. - Customize the button by setting the properties of the GIDSignInButton object.
- In your view controller, declare the sign-in button as a property.
3. Authenticate with Firebase
In the signIn:didSignInForUser:withError:
method, get a Google ID token
and Google access token from the GIDAuthentication
object and
exchange them for a Firebase credential:
Swift
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) { // ... if let error = error { // ... return } guard let authentication = user.authentication else { return } let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken, accessToken: authentication.accessToken) // ... }
Objective-C
- (void)signIn:(GIDSignIn *)signIn didSignInForUser:(GIDGoogleUser *)user withError:(NSError *)error { // ... if (error == nil) { GIDAuthentication *authentication = user.authentication; FIRAuthCredential *credential = [FIRGoogleAuthProvider credentialWithIDToken:authentication.idToken accessToken:authentication.accessToken]; // ... } else { // ... } }
Finally, authenticate with Firebase using the credential:
Swift
Auth.auth().signIn(with: credential) { (authResult, error) in if let error = error { let authError = error as NSError if (isMFAEnabled && authError.code == AuthErrorCode.secondFactorRequired.rawValue) { // The user is a multi-factor user. Second factor challenge is required. let resolver = authError.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver var displayNameString = "" for tmpFactorInfo in (resolver.hints) { displayNameString += tmpFactorInfo.displayName ?? "" displayNameString += " " } self.showTextInputPrompt(withMessage: "Select factor to sign in\n\(displayNameString)", completionBlock: { userPressedOK, displayName in var selectedHint: PhoneMultiFactorInfo? for tmpFactorInfo in resolver.hints { if (displayName == tmpFactorInfo.displayName) { selectedHint = tmpFactorInfo as? PhoneMultiFactorInfo } } PhoneAuthProvider.provider().verifyPhoneNumber(with: selectedHint!, uiDelegate: nil, multiFactorSession: resolver.session) { verificationID, error in if error != nil { print("Multi factor start sign in failed. Error: \(error.debugDescription)") } else { self.showTextInputPrompt(withMessage: "Verification code for \(selectedHint?.displayName ?? "")", completionBlock: { userPressedOK, verificationCode in let credential: PhoneAuthCredential? = PhoneAuthProvider.provider().credential(withVerificationID: verificationID!, verificationCode: verificationCode!) let assertion: MultiFactorAssertion? = PhoneMultiFactorGenerator.assertion(with: credential!) resolver.resolveSignIn(with: assertion!) { authResult, error in if error != nil { print("Multi factor finanlize sign in failed. Error: \(error.debugDescription)") } else { self.navigationController?.popViewController(animated: true) } } }) } } }) } else { self.showMessagePrompt(error.localizedDescription) return } // ... return } // User is signed in // ... }
Objective-C
[[FIRAuth auth] signInWithCredential:credential completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) { if (isMFAEnabled && error && error.code == FIRAuthErrorCodeSecondFactorRequired) { FIRMultiFactorResolver *resolver = error.userInfo[FIRAuthErrorUserInfoMultiFactorResolverKey]; NSMutableString *displayNameString = [NSMutableString string]; for (FIRMultiFactorInfo *tmpFactorInfo in resolver.hints) { [displayNameString appendString:tmpFactorInfo.displayName]; [displayNameString appendString:@" "]; } [self showTextInputPromptWithMessage:[NSString stringWithFormat:@"Select factor to sign in\n%@", displayNameString] completionBlock:^(BOOL userPressedOK, NSString *_Nullable displayName) { FIRPhoneMultiFactorInfo* selectedHint; for (FIRMultiFactorInfo *tmpFactorInfo in resolver.hints) { if ([displayName isEqualToString:tmpFactorInfo.displayName]) { selectedHint = (FIRPhoneMultiFactorInfo *)tmpFactorInfo; } } [FIRPhoneAuthProvider.provider verifyPhoneNumberWithMultiFactorInfo:selectedHint UIDelegate:nil multiFactorSession:resolver.session completion:^(NSString * _Nullable verificationID, NSError * _Nullable error) { if (error) { [self showMessagePrompt:error.localizedDescription]; } else { [self showTextInputPromptWithMessage:[NSString stringWithFormat:@"Verification code for %@", selectedHint.displayName] completionBlock:^(BOOL userPressedOK, NSString *_Nullable verificationCode) { FIRPhoneAuthCredential *credential = [[FIRPhoneAuthProvider provider] credentialWithVerificationID:verificationID verificationCode:verificationCode]; FIRMultiFactorAssertion *assertion = [FIRPhoneMultiFactorGenerator assertionWithCredential:credential]; [resolver resolveSignInWithAssertion:assertion completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) { if (error) { [self showMessagePrompt:error.localizedDescription]; } else { NSLog(@"Multi factor finanlize sign in succeeded."); } }]; }]; } }]; }]; } else if (error) { // ... return; } // User successfully signed in. Get user data from the FIRUser object if (authResult == nil) { return; } FIRUser *user = authResult.user; // ... }];
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.