Skip to main content
← Blog
Desarrollo

Firebase for Xamarin.Forms — Part 2: FirebaseAuth for iOS

4 min read
Firebase for Xamarin.Forms — Part 2: FirebaseAuth for iOS

In the previous article we implemented Firebase.Auth for Android. Today we continue with the iOS implementation.

Firebase Console setup

The setup mirrors what we did for Android — go to https://firebase.google.com, open your project, and this time click “Add Firebase to your iOS app.” The file you’ll download and save is GoogleService-Info.plist instead of google-services.json.

Configuring the Xamarin.Forms project

Add GoogleService-Info.plist to your iOS project and set its build action to BundleResource.

Add the required NuGet packages:

  • Xamarin.Firebase.iOS.Auth — Firebase authentication
  • Xamarin.Auth — Google authentication

Update Entitlements.plist to allow credential storage — enable Keychain. If you’re unsure how, follow Xamarin’s entitlements guide.

Add a URL scheme entry to Info.plist with two values:

  1. Your app’s bundle identifier
  2. The REVERSED_CLIENT_ID value from GoogleService-Info.plist

This is required for Google Sign-In’s redirect URL handling.

Initializing Firebase

In AppDelegate.cs, update FinishedLaunching:

public override bool FinishedLaunching(UIApplication app, NSDictionary options) {
    global::Xamarin.Forms.Forms.Init();
    LoadApplication(new App());
    Firebase.Core.App.Configure();
    return base.FinishedLaunching(app, options);
}

Service implementation

Create the iOS implementation of IFirebaseAuthService using dependency injection (the same interface defined in the shared project).

IsUserSigned

public bool IsUserSigned() {
    var user = Auth.DefaultInstance.CurrentUser;
    return user != null;
}

SignIn

Firebase iOS uses callbacks rather than async/await, so we need a small workaround to return a Task<bool>:

private static bool loginResult = false;
CancellationTokenSource tokenSource = new CancellationTokenSource();
CancellationToken token;
Task t;

public async Task<bool> SignIn(string email, string password) {
    Auth.DefaultInstance.SignIn(email, password, HandleAuthResultLoginHandler);
    token = tokenSource.Token;
    t = Task.Factory.StartNew(async () => {
        await Task.Delay(4000);
    }, token).Unwrap();
    await t;
    return loginResult;
}

private void HandleAuthResultLoginHandler(User user, Foundation.NSError error) {
    if (error != null) {
        loginResult = false;
    } else {
        loginResult = true;
    }
    tokenSource.Cancel();
}

The pattern: start a task that waits up to 4 seconds, then cancel it as soon as the callback fires. I prefer keeping the callback in a separate named method, but you can use an anonymous lambda if you prefer.

SignUp

Same pattern as SignIn:

private static bool signUpResult = false;

public async Task<bool> SignUp(string email, string password) {
    Auth.DefaultInstance.CreateUser(email, password, HandleAuthResultHandlerSignUp);
    token = tokenSource.Token;
    t = Task.Factory.StartNew(async () => {
        await Task.Delay(4000);
    }, token).Unwrap();
    await t;
    return signUpResult;
}

private void HandleAuthResultHandlerSignUp(User user, Foundation.NSError error) {
    signUpResult = error == null;
    tokenSource.Cancel();
}

Logout

public async Task<bool> Logout() {
    NSError error;
    var signedOut = Auth.DefaultInstance.SignOut(out error);
    return signedOut;
}

Google Sign-In for iOS

This was the trickiest part. We use Xamarin.Auth’s OAuth2Authenticator:

public static OAuth2Authenticator XAuth;

public void SignInWithGoogle() {
    XAuth = new OAuth2Authenticator(
        clientId: "2485447395-h5buvvf05c44j54cmlg3qcnrndi0fd99.apps.googleusercontent.com",
        clientSecret: "",
        scope: "profile",
        authorizeUrl: new Uri("https://accounts.google.com/o/oauth2/v2/auth"),
        redirectUrl: new Uri("com.googleusercontent.apps.2485447395-h5buvvf05c44j54cmlg3qcnrndi0fd99:/oauth2redirect"),
        accessTokenUrl: new Uri("https://www.googleapis.com/oauth2/v4/token"),
        isUsingNativeUI: true);

    var window = UIApplication.SharedApplication.KeyWindow;
    var vc = window.RootViewController;
    XAuth.Completed += OnAuthenticationCompleted;
    XAuth.Error += OnAuthenticationFailed;
    var viewController = XAuth.GetUI();
    vc.PresentViewController(viewController, true, null);
}

Where:

  • clientId — from GoogleService-Info.plist
  • redirectUrlREVERSED_CLIENT_ID from GoogleService-Info.plist + :/oauth2redirect

This opens Safari for Google account selection. Handle the return URL in AppDelegate:

// iOS 9+
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options) {
    Uri uri_netfx = new Uri(url.AbsoluteString);
    FirebaseAuthService.XAuth.OnPageLoading(uri_netfx);
    return true;
}

// iOS 8 and older
public override bool OpenUrl(UIApplication application, NSUrl url,
                              string sourceApplication, NSObject annotation) {
    Uri uri_netfx = new Uri(url.AbsoluteString);
    FirebaseAuthService.XAuth.OnPageLoading(uri_netfx);
    return true;
}

Handle the authentication result:

private void OnAuthenticationCompleted(object sender, AuthenticatorCompletedEventArgs e) {
    var window = UIApplication.SharedApplication.KeyWindow;
    var vc = window.RootViewController;
    vc.DismissViewController(true, null);

    if (e.IsAuthenticated) {
        var id_token = e.Account.Properties["id_token"];
        var access_token = e.Account.Properties["access_token"];
        MessagingCenter.Send(FirebaseAuthService.KEY_AUTH,
                             FirebaseAuthService.KEY_AUTH,
                             id_token + "###" + access_token);
    }
}

private void OnAuthenticationFailed(object sender, AuthenticatorErrorEventArgs e) {
    var window = UIApplication.SharedApplication.KeyWindow;
    var vc = window.RootViewController;
    vc.DismissViewController(true, null);
}

Finally, sign into Firebase with the retrieved credentials:

public async Task<bool> SignInWithGoogle(string tokenId) {
    String[] tokens = tokenId.Split(new string[] { "###" }, StringSplitOptions.None);
    var credential = GoogleAuthProvider.GetCredential(tokens[0], tokens[1]);
    Auth.DefaultInstance.SignIn(credential, HandleAuthResultHandlerGoogleSignin);
    token = tokenSource.Token;
    t = Task.Factory.StartNew(async () => {
        await Task.Delay(4000);
    }, token).Unwrap();
    await t;
    return loginResult;
}

With that, the complete login system is working — email/password and Google Sign-In, on both Android and iOS.

Download the current project: https://github.com/jamontes79/xamarin-forms-firebase-sample/tree/1637d1b1bd2e9cfb79b5cff5a144175265c7a7a8

In the next article we’ll start implementing Firebase Database.


More in Desarrollo