tl dr; give me repo? Ok 😎
Introduction
In this blogpost I'll describe using SignalR with Firebase Authentication and Google as a provider. I've seen a lot of blog posts about Firebase and SignalR but they covered only simple e-mail/password authentication.
I assume that you already have your Firebase project up and running, and Google Authentication provider is added.
Let's start with the server
Program.cs
First of all we have to create ASP.NET Core 6 project.
Let's use ASP.NET Core Empty. We're welcomed with minimalistic .NET 6 Program.cs
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
There is very usefull NuGet Package for using Firebase Auth in ASP.NET Core. So let's add it using our NuGet Package manager:
AspNetCore.Firebase.Authentication consist only of 2 extension methods so it's also good idea to copy it directly to your code base and get rid of this one dependency.
Now let's add SignalR and FirebaseAuthentication to our services altogether with Authentication and Authorization middleware, so our Program.cs will look like:
using AspNetCore.Firebase.Authentication.Extensions;
using ViralBlog.Server;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSignalR();
builder.Services.AddFirebaseAuthentication("https://securetoken.google.com/your-project-name", "your-project-name");
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.MapHub<MessagingHub>("/messaging");
app.UseAuthentication();
app.UseAuthorization();
app.Run();
Need for Hub
Our next step is to create SignalR Hub. What is Hub? Click here to learn more.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;
namespace ViralBlog.Server;
[Authorize]
public class MessagingHub : Hub
{
public void SendMessage(string message) => Console.WriteLine(message);
}
Server side? Done.
Xamarin App
Take off
Create Xamarin app project Mobile App (Xamarin.Forms) and select blank template. By default iOS and Android projects are selected, keep it that way.
Login Page
Let's start with simple Login page
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="GC.SgnlR.MainPage">
<Grid RowDefinitions="auto, *" BackgroundColor="#85C8DB">
<Frame Grid.Row="0"
BackgroundColor="#4B799A"
VerticalOptions="StartAndExpand">
<Label Text="Welcome to Git Commit!"
HorizontalTextAlignment="Center"
TextColor="White"
FontSize="36"/>
</Frame>
<Button Grid.Row="1"
Padding="16"
CornerRadius="16"
VerticalOptions="Center"
Clicked="Button_Clicked"
Text="Login with Google"
BackgroundColor="#C3A5C0"/>
</Grid>
</ContentPage>
Preview:
Ok this needs more refinement... Luckily for me I know amazing UX/UI designer that helped me with this, simple but looks great! Thanks Klaudia Keil!
This obviously looks so much better 🔥 If you want code just look it up in repo.
IGoogleAuth
We'll need abstraction that will be used in shared code layer to Authenticate via Google.
To utilize OAuth2Authenticator class you'll have to add this NuGet:
It's taken care by Microsoft and has 1.8M downloads. For me it's pretty legit. Add it to shared project and Android and iOS as well.
iOS
We have to implement interface mentioned above in the iOS project
Ok so you probably wonder... How do I get ClientId and RedirectUrl?
Easy, just go to your Firebase project main screen -> Add app -> iOS -> fill needed properties and register app -> Download config file.
Add this file to iOS project as it is shown in the Firebase. In this file you'll be able to find ClientId, your RedirectUrl is: "REVERSED_CLIENT_ID:/oauth2redirect"
Register our service in AppDelegate.FinishedLaunching method
DependencyService.Register<IGoogleAuth, GoogleAuth>();
Back to the MainPage.cs but code behind, we want to Login after clicking the button
using System;
using Xamarin.Auth;
using Xamarin.Forms;
namespace GC.SignalR
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
var googleAuth = DependencyService.Resolve<IGoogleAuth>();
googleAuth.AuthSuccess += GoogleAuth_AuthSuccess;
googleAuth.AuthFailure += GoogleAuth_AuthFailure;
}
private void Button_Clicked(object sender, EventArgs e)
{
googleAuth.LoginAsync();
}
private void GoogleAuth_AuthFailure(object sender, AuthenticatorCompletedEventArgs e)
{
DisplayAlert("Login Failure!", null, "Ok");
}
private async void GoogleAuth_AuthSuccess(object sender, AuthenticatorCompletedEventArgs e)
{
await DisplayAlert("Success!", null, "Ok");
}
}
}
Okaaay! So let's try it!
Okay okay... after pressing Login button we see Google's login page. Yay! But after login we're stuck at Google's homepage and after clicking Done we're said that Auth failed. Why?
Our app doesn't know how to utilize redirect Url scheme, let's fix that!
We have to add custom scheme to our Info.plist. Double click on Info.plist -> Advanced -> URL Types -> Add URL Type.
Identifier: I used my Bundle Identifier
URL Schemes: use REVERSED_CLIENT_ID from GoogleService-Info.plist
Role: Viewer
next override AppDelegate.OpenUrl
Rebuild, deploy... Login... and? It works! After successful login we're redirected back to our app. Â
Firebase Login
Currently we have Google's IdToken and AccessToken, but we need Firebase IdToken. We need now Login to our Firebase.
Right now we'll add official Firebase bindings to our iOS project.
Quick abstraction:
Now implementation:
Remember to register the service, also we have to initialize Firebase 👆
Make use of our brand new service in Login Page's code behind. Change GoogleAuth_AuthSuccess method:
As you can see we're already navigating to Messaging Page
Messaging Page
We'll do only refined version since I prefer my apps looking good 😎
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
x:Class="GC.SgnlR.MessagingPage"
BackgroundImageSource="Background">
<ContentPage.Content>
<Frame CornerRadius="20"
HeightRequest="292"
WidthRequest="308"
VerticalOptions="Center"
HorizontalOptions="Center"
BackgroundColor="#F0F6F8">
<Grid Padding="44,18" RowDefinitions="*,*,*">
<Label Grid.Row="0"
Text="Succesful login!"
VerticalOptions="Center"
FontSize="26"
FontAttributes="Bold"
HorizontalTextAlignment="Center"
TextColor="#000000"/>
<Entry Grid.Row="1"
x:Name="entry"
HeightRequest="44"
VerticalOptions="Center"
BackgroundColor="#FFFFFF"
TextColor="Black"/>
<Button Grid.Row="2"
Clicked="Button_Clicked"
VerticalOptions="Center"
Text="Send message"
TextColor="#FFFFFF"
FontSize="16"
FontAttributes="Bold"
BackgroundColor="#0C3D67"
CornerRadius="15"
HeightRequest="47"
WidthRequest="133"
HorizontalOptions="Center"
xct:ShadowEffect.OffsetY="3"
xct:ShadowEffect.Color="#000000"
xct:ShadowEffect.Opacity="0.16"
xct:ShadowEffect.Radius="6"/>
</Grid>
</Frame>
</ContentPage.Content>
</ContentPage>
Preview:
SignalR Time
To use SignalR we obviously need to add SignalR NuGet package
Messaging Page code behind
using Microsoft.AspNetCore.SignalR.Client;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace GC.SignalR
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MessagingPage : ContentPage
{
private string _token;
private HubConnection _connection;
public MessagingPage()
{
InitializeComponent();
}
private async void Button_Clicked(object sender, EventArgs e)
{
await _connection.InvokeCoreAsync("SendMessage", args: new[] { entry.Text });
}
protected async override void OnAppearing()
{
_token = BindingContext as string;
_connection = new HubConnectionBuilder()
.WithUrl("https://192.168.0.136:45455/messaging", options =>
{
options.AccessTokenProvider = () => Task.FromResult(_token);
options.HttpMessageHandlerFactory = (message) =>
{
if (message is HttpClientHandler clientHandler)
// bypass SSL certificate
clientHandler.ServerCertificateCustomValidationCallback +=
(sender, certificate, chain, sslPolicyErrors) => { return true; };
return message;
};
options.Headers.Add("Authorization", _token);
})
.Build();
await _connection.StartAsync();
base.OnAppearing();
}
}
}
So... are we there yet?
Currently iOS + SignalR + Visual Studio 2022 has some nasty bug that will occur right away when you'll try to connect to your SignalR's Hub:
You can read about bug's current status here:
I can confirm that solution by adding this code to the iOS's csproj works
<ItemGroup>
<PackageReference Include="System.Memory" Version="4.5.4">
<IncludeAssets>none</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Buffers" Version="4.5.1">
<IncludeAssets>none</IncludeAssets>
</PackageReference>
</ItemGroup>
Do I need to add it by hand? Yes.
Does these packages need separated ItemGroup? Yes.
FINALLY
Rebuild, deploy, login, run local SignalR server, et voila!
Cheers! I hope you learned something! 🎉 Subscribe for part 2!