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:
- Your app’s bundle identifier
- The
REVERSED_CLIENT_IDvalue fromGoogleService-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— fromGoogleService-Info.plistredirectUrl—REVERSED_CLIENT_IDfromGoogleService-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.