Firebase Authentication in Xamarin - The User Interface
Google’s Firebase is a fantastic platform for us developers. It provides a wide variety of services that we may need for our applications, ranging from databases and storage, all the way to machine learning services and analytics.
Authentication, of course, is among those services, and it makes it incredibly simple for developers to authenticate users using a variety of methods: from the traditional email and password method to phone number authentication to social media authentication.
In this new series of posts, I will be showing you how to implement Firebase user authentication in your Xamarin Forms apps, starting in this one with the user interface.
True, we will not be using Firebase just yet, but I will cover how to create a Page that doubles as a Login and a Register page.
Getting started
I will be using the MVVM architectural pattern to code the functionality, and in particular, I will be using the INotifyPropertyChanged and the ICommand interfaces that I have covered in previous articles. These interfaces will allow me to efficiently bind the values that the user writes in the text entries to C# properties and to react to the press of a button.
In practice, this means two things:
That when the user types an email in the “Login Page” and realizes that they need to register first, after “navigating” to the “Register Page” the email is still there.
Since we will use platform-specific libraries, the ICommand interface can help us better structure our code for a clear separation of concerns.
Creating the Login Page
I will assume that you are already familiar with the process that you need to follow to create Xamarin Forms applications, so I will just jump right into creating the Page. By default, you will have a MainPage in the root of the .NET Standard Library project, but since we will be using the MVVM pattern, I have:
Created a new Views folder
Deleted the MainPage
Created two new Pages (XAML Pages that is) inside the Views folder
Now, the purpose of this series of posts is only to implement authentication, and we will only work on the Login Page, but typically you want a MainPage that is the first page to be loaded, and only if the user is NOT authenticated, should they be navigated to the Login Page. That is why I have created two pages inside the Views folder.
The Navigation
We have two pages, but right now, our app is not navigating to any of them. If you open the App.xaml.cs file, you will notice that from the constructor, we are still using the old MainPage. But that page no longer exists, so we need to change that. Also, we will need some navigation, which means we need the assistance of the NavigationPage.
We should then initialize the App’s MainPage to be something like this:
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new SubscriptionsPage());
}
Notice that I am not navigating to the LoginPage, but to my other page (which I called SubscriptionsPage, feel free to name yours as you need).
Doing so is a good practice to immediately navigate to the main page and only navigate to the login/register page if necessary. That means that from the main page (my SubscriptionsPage), we will need to evaluate if the user has authenticated themselves and if they have not, navigate to the LoginPage.
Of course, right now, we have no way of knowing if the user has logged in, but we can already add some functionality to the OnAppearing method of our main page.
So, in the main page’s C# file, we can override the OnAppearing method, which executes whenever we navigate to the page. Fittingly, we can evaluate if the user has logged in or not from here:
protected override async void OnAppearing()
{
base.OnAppearing();
if (true) // TODO: Make real evaluation
{
await Task.Delay(300);
await Navigation.PushAsync(new LoginPage());
}
else
{
// TODO: retrieve user's data?
}
}
Eventually, I will need to make real evaluations inside that if statement, but for now, this will work. Every single time the user opens the application, this code will navigate them to the login page.
Incidentally, I am delaying this navigation by a few milliseconds. Adding this delay will ensure that the navigation stack includes the main page so that we can later navigate back to it, don’t forget to include that code or you may run into some issues once you try to navigate back after authenticating the user.
The User Interface
Finally, we can create the User Interface, now that we are navigating to it and we could see the interface when we run the application.
I will assume some familiarity with XAML here but do know that I have defined a couple of StackLayouts inside of a Grid. However, they are not visible at the same time.
I started by defining a Grid with some margin inside the ContentPage’s Content:
<ContentPage.Content>
<Grid Margin="16,0">
</Grid>
</ContentPage.Content>
Login User Interface
Inside of that Grid is where I will define both Stack Layouts. I defined the first one to be the login interface.
<StackLayout x:Name="loginStackLayout"
VerticalOptions="Center"
IsVisible="True">
<Entry Placeholder="Email"
Keyboard="Email"/>
<Entry Placeholder="Password"
IsPassword="True"/>
<Button Text="Login"/>
<StackLayout Orientation="Horizontal">
<Label Text="Don't have an account?"/>
<Label Text="Register"
Style="{StaticResource accentLabel}">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="RegisterLabel_Tapped"/>
</Label.GestureRecognizers>
</Label>
</StackLayout>
</StackLayout>
There are a few things to focus on here:
The StackLayout is named.
The second entry has to hide the characters that are being typed, which I can achieve by setting its IsPassword property to true.
I have used a Gesture recognizer so I can create a Tapped event handler that I can use from the LoginPage’s code-behind (more on that in a second).
I defined a default style for the button and a named style for one of the labels back in the App.xaml file (this is, of course, optional)
The end result is this:
As you may have guessed by now, that register label should somehow display the register interface. Now, I don’t have that interface yet (spoiler, it is going to be another StackLayout inside the Grid that we already have), but what I do have already is a named StackLayout (which means that I can access that element from the code-behind) and a gesture recognizer with an event handler (which means I need to add the actual event handler in the C# file).
It is inside that event handler that I can hide this StackLayout when the “Register” label is tapped, and display the other stack layout:
void RegisterLabel_Tapped(object sender, EventArgs args)
{
registerStackLayout.IsVisible = true;
loginStackLayout.IsVisible = false;
}
You guessed it, the other stack layout will be called registerStackLayout.
Register User Interface
Now we can define that registerStackLayout. Right bellow the loginStackLayout, but inside the Grid, I will add another StackLayout that I will hide by default by setting its IsVisible property to false:
<StackLayout x:Name="registerStackLayout"
VerticalOptions="Center"
IsVisible="False">
<Entry Placeholder="Name"/>
<Entry Placeholder="Email"
Keyboard="Email"/>
<Entry Placeholder="Password"
IsPassword="True"/>
<Entry Placeholder="Confirm password"
IsPassword="True"/>
<Button Text="Register"/>
<StackLayout Orientation="Horizontal">
<Label Text="Already have an account?"/>
<Label Text="Login"
Style="{StaticResource accentLabel}">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="LoginLabel_Tapped"/>
</Label.GestureRecognizers>
</Label>
</StackLayout>
</StackLayout>
The new stack layout looks somewhat similar to the previous one. I only added a couple of other entries, and the labels say something different, but I also have some styles in there, and another gesture recognizer. And indeed, that other gesture recognizer needs its event handler, which will, in turn, hide this new stack layout and display our previous loginStackLayout:
void LoginLabel_Tapped(object sender, EventArgs args)
{
registerStackLayout.IsVisible = false;
loginStackLayout.IsVisible = true;
}
The result is an app that navigates to our LoginPage from the main page, displays the login UI by default, but can hide/show the login and register views accordingly.
Handling user input
Now that we have the user interface it is time to start using the INotifyPropertyChanged. To learn more about the interface feel free to check this other article I have, but that interface will enable us to implement the first bits of the MVVM pattern.
Let’s start by creating a new folder from the root of the .NET Standard library, a new ViewModel folder. And inside this folder, a new LoginVM class. This is the class that will contain the logic for our LoginPage, and it is this class the one that will implement the INotifyPropertyChanged:
public class LoginVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Notice that in addition to the PropertyChanged event, which is a member of the interface, I created an OnPropertyChanged method that will make it easy for me to raise the event from the setter of every property that I need. Which brings me to those properties, I need a property for every entry that I have back in the interface, or rather, for the Name entry, the Email entries (I will treat both the email entry from the login UI and the register UI as one), the password entries (same as the email entries) and the confirm password entry:
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
OnPropertyChanged("Name");
}
}
private string email;
public string Email
{
get
{
return email;
}
set
{
email = value;
OnPropertyChanged("Email");
}
}
private string password;
public string Password
{
get
{
return password;
}
set
{
password = value;
OnPropertyChanged("Password");
}
}
private string confirmPassword;
public string ConfirmPassword
{
get
{
return confirmPassword;
}
set
{
confirmPassword = value;
OnPropertyChanged("ConfirmPassword");
}
}
Having the code like this means that every time a property changes (the setter is called) we raise the PropertyChanged event, which can update the view accordingly. We can now bind all of these properties back in the XAML file.
Binding the properties
We need access to these new properties from the XAML file, which means that we will need to create a LoginVM resource. To achieve this from the LoginPage.xaml we first need access to the LoginVM class. Since it exists in a different namespace, we need to add a namespace reference when defining the ContentPage itself:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:MySubscriptions.ViewModel"
x:Class="MySubscriptions.View.LoginPage">
Notice that vm namespace reference. That is the one pointing to the ViewModel namespace. Once we have this, we can create a new LoginVM resource:
<ContentPage.Resources>
<ResourceDictionary>
<vm:LoginVM x:Key="vm"/>
</ResourceDictionary>
</ContentPage.Resources>
The last thing that we need is to set this new resource as the binding context for all the elements in the page, so they can access the properties. Since the binding context is inherited to children, we can set the binding context directly inside of the Grid like this (since the Grid is the parent of all other elements):
<Grid Margin="16,0"
BindingContext="{StaticResource vm}">
Finally, we can access all the LoginVM properties and bind them where needed. For example, the email entries will look like this:
<Entry Placeholder="Email"
Keyboard="Email"
Text="{Binding Email, Mode=TwoWay}"/>
Binding the Email property to the Text property in a TwoWay mode means that every time we change the Email property from C# it will update the Text in this entry, and every time the user changes the text that is written inside this entry, the Email property will also be updated. The entire content looks like this:
<ContentPage.Content>
<Grid Margin="16,0"
BindingContext="{StaticResource vm}">
<StackLayout x:Name="loginStackLayout"
VerticalOptions="Center"
IsVisible="True">
<Entry Placeholder="Email"
Keyboard="Email"
Text="{Binding Email, Mode=TwoWay}"/>
<Entry Placeholder="Password"
Text="{Binding Password, Mode=TwoWay}"
IsPassword="True"/>
<Button Text="Login"/>
<StackLayout Orientation="Horizontal">
<Label Text="Don't have an account?"/>
<Label Text="Register"
Style="{StaticResource accentLabel}">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="RegisterLabel_Tapped"/>
</Label.GestureRecognizers>
</Label>
</StackLayout>
</StackLayout>
<StackLayout x:Name="registerStackLayout"
VerticalOptions="Center"
IsVisible="False">
<Entry Placeholder="Name"
Text="{Binding Name, Mode=TwoWay}"/>
<Entry Placeholder="Email"
Keyboard="Email"
Text="{Binding Email, Mode=TwoWay}"/>
<Entry Placeholder="Password"
Text="{Binding Password, Mode=TwoWay}"
IsPassword="True"/>
<Entry Placeholder="Confirm password"
Text="{Binding ConfirmPassword, Mode=TwoWay}"
IsPassword="True"/>
<Button Text="Register"/>
<StackLayout Orientation="Horizontal">
<Label Text="Already have an account?"/>
<Label Text="Login"
Style="{StaticResource accentLabel}">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="LoginLabel_Tapped"/>
</Label.GestureRecognizers>
</Label>
</StackLayout>
</StackLayout>
</Grid>
</ContentPage.Content>
Reacting to button taps
The last step in this article is to react to the press of the login or register buttons. We won’t have the functionality just yet, but we can have the methods ready so we can later focus on implementing the functionality and not reacting to the interactions from the user.
For this, we will use the ICommand interface (feel free to refer back to this article for more information on the ICommand).
Back in the LoginVM we will need two new properties of type ICommand, each will handle one of the buttons:
public ICommand LoginCommand { get; set; }
public ICommand RegisterCommand { get; set; }
These properties need to be initialized from the constructor. Xamarin makes it super easy to work with the ICommand interface by providing a Command class. All we need to do is initialize our properties to a new Command and provide the name of the method that we want to execute when the buttons are pressed:
public LoginVM()
{
LoginCommand = new Command(Login);
RegisterCommand = new Command(Register);
}
private async void Register(object parameter)
{
if (ConfirmPassword != Password)
await App.Current.MainPage.DisplayAlert("Error", "Passwords do not match", "Ok");
else
{
bool result = true; // TODO: actually register
if (result)
await Application.Current.MainPage.Navigation.PopAsync();
}
}
private async void Login(object parameter)
{
bool result = true; // TODO: actually login
if (result)
await Application.Current.MainPage.Navigation.PopAsync();
}
Notice that in those methods I:
Evaluate if the passwords match when registering.
Navigate back to the previous page (main page) if the result is true.
Always set the result to true, but have to implement the functionality later.
That’s it! The methods will be called accordingly when one of those commands is called.
But when are those commands called?
The last step is to bind these new properties to the commands of the buttons that we have in the XAML file, very similar to how we just bound the other properties. So the login button now looks like this:
<Button Text="Login"
Command="{Binding LoginCommand}"/>
And the register button now looks like this:
<Button Text="Register"
Command="{Binding RegisterCommand}"/>
And now we are ready to implement the Firebase Authentication functionality. That is something for the next article.
(Optional) Only enable login/register when the user has written in all entries
If you don’t want the login button to be enabled if the email or password are not filled up, or the register button to be enabled if any entry is empty, you can use the command parameter.
Basically, we need a bindable boolean property that defines whether or not we can login, and another one for the can register.
public bool CanLogin
{
get
{
return !string.IsNullOrEmpty(Email) && !string.IsNullOrEmpty(Password);
}
}
public bool CanRegister
{
get
{
return !string.IsNullOrEmpty(Email) && !string.IsNullOrEmpty(Password) && !string.IsNullOrEmpty(ConfirmPassword) && !string.IsNullOrEmpty(Name);
}
}
Something like this! I am using the other properties to evaluate if the user has filled up the required entries. Email and Password for the login, all of them for the Register.
Now I can bind these new properties to the command parameters of my buttons:
<!--The login button-->
<Button Text="Login"
Command="{Binding LoginCommand}"
CommandParameter="{Binding CanLogin}"/>
<!--The register button-->
<Button Text="Register"
Command="{Binding RegisterCommand}"
CommandParameter="{Binding CanRegister}"/>
Next I need to raise the PropertyChanged event for when these properties change. But since these properties depend on others (and don’t even have a setter), I can call the OnPropertyChanged with the names of my new properties from the other setters. I want the CanLogin to be raised when the Email and Password properties change, and the CanRegister to be raised for every property, so I end up with something like this:
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
OnPropertyChanged("Name");
OnPropertyChanged("CanRegister");
}
}
private string email;
public string Email
{
get
{
return email;
}
set
{
email = value;
OnPropertyChanged("Email");
OnPropertyChanged("CanLogin");
OnPropertyChanged("CanRegister");
}
}
private string password;
public string Password
{
get
{
return password;
}
set
{
password = value;
OnPropertyChanged("Password");
OnPropertyChanged("CanLogin");
OnPropertyChanged("CanRegister");
}
}
private string confirmPassword;
public string ConfirmPassword
{
get
{
return confirmPassword;
}
set
{
confirmPassword = value;
OnPropertyChanged("ConfirmPassword");
OnPropertyChanged("CanRegister");
}
}
Now, the CanLogin and CanRegister will notify the view of any change in their values, which means that I can evaluate if the buttons should be enabled depending on the value from these properties.
Again, the Command class makes it super easy. The constructor can take a second argument, so we can define a CanExecute method that returns a boolean value which defines the state of the command. When initializing our commands then, we can pass a second method:
LoginCommand = new Command(Login, LoginCanExecute);
RegisterCommand = new Command(Register, RegisterCanExecute);
These two new methods only need to return the CanLogin or CanRegister properties that we already have.
private bool LoginCanExecute(object parameter)
{
return CanLogin;
}
private bool RegisterCanExecute(object parameter)
{
return CanRegister;
}
And there you go, now the methods will be enabled only when the corresponding entries have been filled out by the user.