Skip to content

Commit aed2500

Browse files
authored
MAUI BH+BWA+Identity article (#34944)
1 parent bfcf5fd commit aed2500

File tree

4 files changed

+243
-1
lines changed

4 files changed

+243
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
---
2+
title: .NET MAUI Blazor Hybrid and Web App with ASP.NET Core Identity
3+
author: guardrex
4+
description: Learn how to build a .NET MAUI Blazor Hybrid app with a Blazor Web App that manages authentication with ASP.NET Core Identity.
5+
monikerRange: '>= aspnetcore-9.0'
6+
ms.author: riande
7+
ms.custom: mvc
8+
ms.date: 03/12/2025
9+
uid: blazor/hybrid/security/maui-blazor-web-identity
10+
---
11+
# .NET MAUI Blazor Hybrid and Web App with ASP.NET Core Identity
12+
13+
<!-- UPDATE 10.0 - Uncomment at 10.0
14+
15+
[!INCLUDE[](~/includes/not-latest-version.md)]
16+
17+
-->
18+
19+
This sample app demonstrates how to build a .NET MAUI Blazor Hybrid app with a Blazor Web App that uses ASP.NET Core Identity. It shows how to share common UI and authenticate with ASP.NET Core Identity local accounts. Although ASP.NET Core Identity is used, you can use this pattern for any authentication provider from a MAUI Blazor Hybrid client.
20+
21+
The sample:
22+
23+
* Sets up the UI to show or hide pages based on user authentication.
24+
* Sets up ASP.NET Core Identity endpoints for remote clients.
25+
* Logs users in, logs users out, and refreshes tokens from the MAUI client.
26+
* Saves and retrieves tokens in secure device storage.
27+
* Calls a secure endpoint (`/api/weather`) from the client for weather data.
28+
29+
## Prerequisites and preliminary steps
30+
31+
For prerequisites and preliminary steps, see <xref:blazor/hybrid/tutorials/maui>. We recommend using the MAUI Blazor Hybrid tutorial to set up your local system for MAUI development before using the guidance in this article and the sample app.
32+
33+
## Sample app
34+
35+
[Obtain the sample app](xref:blazor/fundamentals/index#sample-apps) in the `MauiBlazorWebIdentity` folder of the [Blazor samples GitHub repository (`dotnet/blazor-samples`)](https://github.com/dotnet/blazor-samples) (.NET 9 or later).
36+
37+
The sample app is a starter solution that contains a native, cross-platform MAUI Blazor Hybrid app, a Blazor Web App, and a Razor class library (RCL) that contains the shared UI (Razor components) used by the native and web apps.
38+
39+
1. Clone this repository or download a ZIP archive of the repository. For more information, see [How to download a sample](xref:index#how-to-download-a-sample).
40+
1. Make sure you have [.NET 9 and the MAUI workload installed (.NET MAUI documentation)](/dotnet/maui/get-started/installation).
41+
1. Open the solution in Visual Studio (2022 or later) or VS Code with the .NET MAUI extension installed.
42+
1. Set the `MauiBlazorWeb` MAUI project as the startup project. In Visual Studio, right-click the project and select **Set as Startup Project**.
43+
1. Start the `MauiBlazorWeb.Web` project without debugging. In Visual Studio, right-click on the project and select **Debug** > **Start without Debugging**.
44+
1. Inspect the Identity endpoints by navigating to `https://localhost:7157/swagger` in a browser.
45+
1. Navigate to `https://localhost:7157/account/register` to register a user in the Blazor Web App. Immediately after the user is registered, use the **Click here to confirm your account** link in the UI to confirm the user's email address because a real email sender isn't registered for account confirmation.
46+
1. Start (`F5`) the `MauiBlazorWeb` MAUI project. You can set the debug target to either **Windows** or an Android emulator.
47+
1. Notice you can only see the `Home` and `Login` pages.
48+
1. Log in with the user that you registered.
49+
1. Notice you can now see the shared `Counter` and `Weather` pages.
50+
1. Log out and notice you can only see the `Home` and `Login` pages again.
51+
1. Navigate to `https://localhost:7157/` in a browser and the web app behaves the same.
52+
53+
## Shared UI
54+
55+
The shared UI is in the `MauiBlazorWeb.Shared` project. This project contains the Razor components that are shared between the MAUI and Blazor Web App projects (Home, Counter and Weather pages). The `Counter` component and `Weather` component are protected by [`[Authorize]` attributes](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute), so users can't navigate to them unless they're logged into the app.
56+
57+
In the [Razor directives](xref:blazor/components/index#razor-syntax) at the tops of the `Counter` component (`MauiBlazorWeb.Shared/Pages/Counter.razor`) and `Weather` component (`MauiBlazorWeb.Shared/Pages/Weather.razor`) files:
58+
59+
```razor
60+
@using Microsoft.AspNetCore.Authorization
61+
@attribute [Authorize]
62+
```
63+
64+
## MAUI app and Blazor Web App routing
65+
66+
The `Routes` component uses an <xref:Microsoft.AspNetCore.Components.Authorization.AuthorizeRouteView> to route users based on their authentication status. If a user isn't authenticated, they're redirected to the `Login` page. For more information, see <xref:blazor/security/index#customize-unauthorized-content-with-the-router-component>.
67+
68+
In `MauiBlazorWeb.Web/Components/Routes.razor`:
69+
70+
```razor
71+
<AuthorizeRouteView ...>
72+
<Authorizing>
73+
Authorizing...
74+
</Authorizing>
75+
<NotAuthorized>
76+
<Login />
77+
</NotAuthorized>
78+
</AuthorizeRouteView>
79+
```
80+
81+
The [`NavMenu` component](xref:blazor/project-structure#blazor-web-app) contains the navigation menu that uses an [`AuthorizeView` component](xref:blazor/security/index#authorizeview-component) to show or hide links based on the user's authentication status.
82+
83+
In `MauiBlazorWeb.Web/Components/Layout/NavMenu.razor`:
84+
85+
```razor
86+
<AuthorizeView>
87+
<NotAuthorized>
88+
...
89+
</NotAuthorized>
90+
<Authorized>
91+
...
92+
</Authorized>
93+
</AuthorizeView>
94+
```
95+
96+
### Server project
97+
98+
The Blazor Web App project (`MauiBlazorWeb.Web`) of the sample app contains the ASP.NET Core Identity pages and uses the <xref:Microsoft.AspNetCore.Identity.SignInManager%601> framework class to manage logins and users on the server. In order for the MAUI client (or any external client) to authenticate, the Identity endpoints must be registered and exposed. In the `Program` file, Identity endpoints are set up with the calls to:
99+
100+
* <xref:Microsoft.Extensions.DependencyInjection.IdentityServiceCollectionExtensions.AddIdentityApiEndpoints%2A>
101+
* <xref:Microsoft.AspNetCore.Routing.IdentityApiEndpointRouteBuilderExtensions.MapIdentityApi%2A>
102+
* `MapAdditionalIdentityEndpoints` (`MauiBlazorWeb.Web/Components/Account/IdentityComponentsEndpointRouteBuilderExtensions.cs`).
103+
104+
In `MauiBlazorWeb.Web/Program.cs`:
105+
106+
```csharp
107+
builder.Services.AddIdentityApiEndpoints<ApplicationUser>(...)
108+
.AddEntityFrameworkStores<ApplicationDbContext>();
109+
110+
...
111+
112+
app.MapGroup("/identity").MapIdentityApi<ApplicationUser>();
113+
114+
...
115+
116+
app.MapAdditionalIdentityEndpoints();
117+
```
118+
119+
> [!IMPORTANT]
120+
> ASP.NET Core Identity pages and the implementation of the <xref:Microsoft.AspNetCore.Identity.SignInManager%601> framework class to manage logins and users is generated automatically when you create a a project from the Blazor Web App project template with **Individual Accounts**.
121+
>
122+
> This article focuses on using the provided sample app; but when creating a new project from the Blazor Web App template, you must remove the generated call to <xref:Microsoft.AspNetCore.Identity.IdentityCookieAuthenticationBuilderExtensions.AddIdentityCookies%2A> on <xref:Microsoft.Extensions.DependencyInjection.AuthenticationServiceCollectionExtensions.AddAuthentication%2A>. The call isn't necessary when implementing API such as `MapAdditionalIdentityEndpoints` in the sample app and results in an error if left in the app.
123+
124+
### Log in from the MAUI client
125+
126+
The `Login` component (`/identity/login` endpoint) is where the user logs in. The component injects the `MauiAuthenticationStateProvider` (`MauiBlazorWeb/Services/MauiAuthenticationStateProvider.cs`) and uses the <xref:Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider> to authenticate the user and redirect them to the homepage if successful. When the state changes, the [`AuthorizeView` component](xref:blazor/security/index#authorizeview-component) shows the appropriate links based on the user's authentication status.
127+
128+
In `MauiBlazorWeb/Components/Pages/Login.razor`:
129+
130+
```csharp
131+
private async Task LoginUser()
132+
{
133+
await AuthStateProvider.LogInAsync(LoginModel);
134+
135+
if (AuthStateProvider.LoginStatus != LoginStatus.Success)
136+
{
137+
loginFailureHidden = false;
138+
return;
139+
}
140+
141+
Navigation.NavigateTo("");
142+
}
143+
```
144+
145+
> [!NOTE]
146+
> This sample only implements Login and Logout pages on the MAUI client, but you can build Register and other management pages against the exposed Identity endpoints for more functionality. For more information on Identity endpoints, see <xref:security/authentication/identity/spa>.
147+
148+
### MAUI Authentication State Provider (`MauiAuthenticationStateProvider`)
149+
150+
The `MauiAuthenticationStateProvider` class is responsible for managing the user's authentication state and providing the <xref:Microsoft.AspNetCore.Components.Authorization.AuthenticationState> to the app. The `MauiAuthenticationStateProvider` class uses an <xref:System.Net.Http.HttpClient> to make requests to the server to authenticate the user. For more information, see <xref:blazor/hybrid/security/index?pivots=maui>.
151+
152+
In `MauiBlazorWeb/Services/MauiAuthenticationStateProvider.cs`:
153+
154+
```csharp
155+
private async Task<ClaimsPrincipal> LoginWithProviderAsync(LoginRequest loginModel)
156+
{
157+
var authenticatedUser = _defaultUser;
158+
LoginStatus = LoginStatus.None;
159+
160+
try
161+
{
162+
// Call the Login endpoint and pass the email and password
163+
var httpClient = HttpClientHelper.GetHttpClient();
164+
var loginData = new { loginModel.Email, loginModel.Password };
165+
var response = await httpClient.PostAsJsonAsync(HttpClientHelper.LoginUrl,
166+
loginData);
167+
168+
LoginStatus =
169+
response.IsSuccessStatusCode ? LoginStatus.Success : LoginStatus.Failed;
170+
171+
if (LoginStatus == LoginStatus.Success)
172+
{
173+
// Save token to secure storage so the user doesn't have to login
174+
// every time
175+
var token = await response.Content.ReadAsStringAsync();
176+
_accessToken = await TokenStorage.SaveTokenToSecureStorageAsync(token,
177+
loginModel.Email);
178+
179+
authenticatedUser = CreateAuthenticatedUser(loginModel.Email);
180+
LoginStatus = LoginStatus.Success;
181+
}
182+
else
183+
{
184+
LoginFailureMessage = "Invalid Email or Password. Please try again.";
185+
LoginStatus = LoginStatus.Failed;
186+
}
187+
}
188+
catch (Exception ex)
189+
{
190+
Debug.WriteLine($"Error logging in: {ex}");
191+
LoginFailureMessage = "Server error.";
192+
LoginStatus = LoginStatus.Failed;
193+
}
194+
195+
return authenticatedUser;
196+
}
197+
```
198+
199+
The `MauiAuthenticationStateProvider` class uses the `HttpClientHelper` (`MauiBlazorWeb/Services/HttpClientHelper.cs`) to handle calling localhost via the emulators and simulators for testing. For more information on calling local services from emulators and simulators, see [Connect to local web services from Android emulators and iOS simulators (.NET MAUI documentation)](/dotnet/maui/data-cloud/local-web-services).
200+
201+
The MAUI Authentication State Provider also uses the `TokenStorage` class (`MauiBlazorWeb/Services/TokenStorage.cs`) that uses [`SecureStorage` API (.NET MAUI documentation)](/dotnet/maui/platform-integration/storage/secure-storage) to store the user's token securely on the device. It refreshes the token near token expiration to avoid user logins.
202+
203+
### MAUI `MauiProgram` file
204+
205+
The MAUI project's `MauiProgram` file (`MauiProgram.cs`) is where the `MauiAuthenticationStateProvider` is registered in the DI container. Authorization core components are also registered, where API such as [`AuthorizeView` component](xref:blazor/security/index#authorizeview-component) are defined.
206+
207+
In `MauiBlazorWeb/MauiProgram.cs`, core functionality is added by calling <xref:Microsoft.Extensions.DependencyInjection.AuthorizationServiceCollectionExtensions.AddAuthorizationCore%2A>:
208+
209+
```csharp
210+
builder.Services.AddAuthorizationCore();
211+
```
212+
213+
Registration of the app's custom <xref:Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider> (`MauiAuthenticationStateProvider`):
214+
215+
```csharp
216+
builder.Services.AddScoped<MauiAuthenticationStateProvider,
217+
MauiAuthenticationStateProvider>();
218+
```
219+
220+
Use the `MauiAuthenticationStateProvider` when the app requires an <xref:Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider>:
221+
222+
```csharp
223+
builder.Services.AddScoped<AuthenticationStateProvider>(s =>
224+
(MauiAuthenticationStateProvider)
225+
s.GetRequiredService<MauiAuthenticationStateProvider>());
226+
```

Diff for: aspnetcore/release-notes/aspnetcore-10.0.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ author: rick-anderson
44
description: Learn about the new features in ASP.NET Core 10.0.
55
ms.author: riande
66
ms.custom: mvc
7-
ms.date: 3/5/2025
7+
ms.date: 3/11/2025
88
uid: aspnetcore-10
99
---
1010
# What's new in ASP.NET Core 10.0
@@ -21,6 +21,12 @@ This section describes new features for Blazor.
2121

2222
[!INCLUDE[](~/release-notes/aspnetcore-10/includes/blazor.md)]
2323

24+
## Blazor Hybrid
25+
26+
This section describes new features for Blazor Hybrid.
27+
28+
[!INCLUDE[](~/release-notes/aspnetcore-10/includes/blazor-hybrid.md)]
29+
2430
## SignalR
2531

2632
This section describes new features for SignalR.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
### New .NET MAUI Blazor Hybrid with a Blazor Web App and ASP.NET Core Identity article and sample
2+
3+
A new article and sample app has been added for .NET MAUI Blazor Hybrid and Web App using ASP.NET Core Identity.
4+
5+
For more information, see the following resources:
6+
7+
* <xref:blazor/hybrid/security/maui-blazor-web-identity>
8+
* [`MauiBlazorWebIdentity` sample app (`dotnet/blazor-samples` GitHub repository)](https://github.com/dotnet/blazor-samples/tree/main/9.0/MauiBlazorWebIdentity)

Diff for: aspnetcore/toc.yml

+2
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,8 @@ items:
450450
uid: blazor/hybrid/security/index
451451
- name: Security considerations
452452
uid: blazor/hybrid/security/security-considerations
453+
- name: .NET MAUI with Blazor Web App and Identity sample
454+
uid: blazor/hybrid/security/maui-blazor-web-identity
453455
- name: Publish
454456
uid: blazor/hybrid/publish/index
455457
- name: Troubleshoot

0 commit comments

Comments
 (0)