Recently I decided to take a deep dive into the world of .NET MAUI Blazor Hybrid to see how it compared to the traditional Xamarin.Forms development that I am so used to. The process for the initial setup was fantastic, and I found the power that was at my fingertips to be quite impressive. However, I was amazed that I couldn't find a solid solution for authentication that would meet my needs, so I thought I'd share it here.
My Goal
The overall architecture of the mobile application I was testing is quite simple. The existing Mobile application presents a login form and calls an API on a .NET Core backend. The API returns a JWT for future API calls, the mobile application stores this in Secure Storage. I wanted to preserve this functionality in my Blazor Hybrid application; however, I also wanted to have the full support of using Authorization in my Razor Components to control what the user sees; otherwise, I would be writing a bunch of my own processes.
Sounds simple, right? Well, yes, but trying to figure out "how" was the complicated part.
My Solution
I was able to get this working with minimal effort. However, I had to piece together information from multiple sources, so I'll document my steps here.
Additional NuGet Packages
I needed to add the following NuGet packages to my project before completing the remaining steps.
- Microsoft.AspNetCore.Authorization
- Microsoft.AspnetCore.Components.Authorization
- Microsoft.AspNetCore.Components.WebAssembly.Authentication
Created a RedirectToLogin.razor Component
This Razor Component was added to manage the redirection of an unauthenticated user to the login page and was added to the project's `/shared` folder.
This simply upon initilization redirects to the /login page.
Updated Main.razor to Enable Authentication
The default template for .NET MAUI Blazor does not include the needed elements for the router to support authorization, so I replaced my main.razor content with the below.
The purpose of this code is to set up default support for AuthorizedRoutes, and when a user isn't authorized, we direct them to our login page.
Set Pages to Require Authorization
The next step was to add the [Authorize] Attribute to my pages that required authentication which was as simple as adding the attribute, similar to the following.
Creation of a Custom AuthenticationStateProvider
The real magic of the implementation was the creation of a Custom AuthenticationStateProvider, which allows me to create and share an identity for the user to show that they are authenticated. I only need to differentiate between authenticated and unauthenticated, but you can support much more. My custom implementation looked like the following:
Usage of this is quite simple where I simply call once a user is authenticated and it stores the JWT in secure storage, which sets the user as authenticated. How you code/implement your /login page is up to you, the key here is that once authenticated, you need to set the value here and then you are set to go. Logout is as simple as removing the items from secure storage.
This is of course, an initial attempted implementation, future implementations can be as complex as needed.
Wire Up Services
The final step, before you can run your application and see the request get redirected to your login component is to add the needed items to MauiProgram.cs, similar to the following.
This simply registers authentication, our custom provider, and sets the expected implementation of AuthenticationStateProvider to be our custom one.
Next Steps
If you complete the following steps and implement a login page of your own you now have a simple method to authenticate via an external service and use that within your Blazor Hybrid application. There is still plenty of work to make sure that this is truly a viable method, but understanding the building blocks necessary, I hope, is helpful. Share any feedback below.
You can view a Sample Implementation of this solution as well.