Add .NET 10 MauiBlazorWebIdentity sample#647
Conversation
Copied 9.0/MauiBlazorWebIdentity and upgraded to .NET 10 with: - All TFMs and packages updated to net10.0/10.0.2 - Identity Schema v3 with passkey support (PasskeySubmit, Passkeys, RenamePasskey) - NotFound page with UseStatusCodePagesWithReExecute - ReconnectModal component - All identity pages updated from official .NET 10 template - Cross-platform DB: SQL Server on Windows, SQLite on macOS/Linux - Bootstrap updated to lib/bootstrap/dist/ (full dist from template) - App.razor: ResourcePreloader, ImportMap, @assets refs - Removed IdentityUserAccessor (replaced by RedirectToInvalidUser) - Removed Tizen platform target - Preserved all MAUI client auth behavior unchanged
- Solution: MauiBlazorWebIdentity.sln (was MauiBlazorWeb.sln) - Shared: MauiBlazorWebIdentity.Shared (was MauiBlazorWeb.Shared) - Web: MauiBlazorWebIdentity.Web (was MauiBlazorWeb.Web) - MAUI: MauiBlazorWebIdentity (was MauiBlazorWeb) - Removed unnecessary nested MauiBlazorWeb/ subfolder - All namespaces updated to match - Differentiates from the non-identity 9.0/MauiBlazorWeb sample
… versions - AddMauiBlazorWebView() was incorrectly renamed during global namespace replace - MAUI packages updated to 10.0.10 (actual available version) - Microsoft.Extensions.Logging.Debug set to 10.0.0
- Add missing 'nav' CSS class to <nav> element in both Web and MAUI NavMenu.razor - Update MAUI MainLayout.razor.css: add 'color-scheme: light only;' - Update MAUI NavMenu.razor.css: height -> min-height
Remove conditional SQL Server/SQLite logic — this is a sample app, no need for cross-platform DB complexity. SQLite works everywhere.
AddIdentityApiEndpoints sets DefaultScheme to BearerAndApplicationScheme (composite scheme for both bearer tokens and cookies). Setting DefaultScheme to ApplicationScheme overrides this and breaks API auth for MAUI clients. Instead, only override DefaultChallengeScheme to ApplicationScheme (cookie), which redirects to /Account/Login on auth challenge while preserving the composite scheme for authentication. This matches the documented pattern from MS Learn for MAUI Blazor Hybrid + Identity apps.
- Move NotFound.razor from Shared to Web project with @layout MainLayout so UseStatusCodePagesWithReExecute renders it with the sidebar/nav - Create MAUI-specific NotFound.razor with @layout MainLayout since Router's NotFoundPage renders outside <Found> (no DefaultLayout) - Update both Routes.razor to reference their local NotFound pages - Remove Shared NotFound.razor to avoid ambiguous route matching
- Style MAUI Login.razor to match web login (form-floating, btn-lg) - Add Remember Me checkbox with conditional token persistence - Add keychain-access-groups entitlement for Mac Catalyst SecureStorage - Extract TokenStorage.DeserializeToken for memory-only token path
905c5cd to
a7a7c25
Compare
|
@BethMassi @mattleibow ... Where are we on this one (and the other one here)? We're still lacking this sample for 10.0, so I'm anxious to get it wrapped up and merged. |
Make safe area CSS rules universal instead of iOS-only (@supports -webkit-touch-callout). This enables proper safe area handling on Android 15+ (API 35+) which enforces edge-to-edge rendering, causing the app content to render behind the status bar. Changes: - Remove @supports (-webkit-touch-callout: none) wrapper so safe area rules apply to both Android and iOS - Change status bar background from #f7f7f7 to rgb(3, 23, 62) to match the sidebar navbar color (gradient start rgb(5,39,103) composited with the top-row overlay rgba(0,0,0,0.4)) - Apply env(safe-area-inset-left) universally for landscape orientation sidebar padding on both platforms See: dotnet/maui#34462 Co-authored-by: Copilot <[email protected]>
|
@guardrex sorry for the delay in getting back to you. I was just doing some more testing and this is ready to go. I just fixed some CSS since last time. It should be an almost identical copy of the .NET 9 sample, but with some new .NET 10 features. |
|
Awesome! Thanks! @halter73 ... Do you want to take a look? |
|
@mattleibow ... Can #590 be closed? |
|
I closed it and will do a new PR based on any extra changes later. |
|
I emailed Stephen, too. Stand-by for a sec to see if he wants to look at this before we merge it. |
guardrex
left a comment
There was a problem hiding this comment.
Never heard back from Stephen. Let's go ahead, and we can react to any feedback he has later.
Overview
This PR adds a new
10.0/MauiBlazorWebIdentitysample — a .NET MAUI Blazor Hybrid app with a companion ASP.NET Core Blazor Web server that shares UI and uses ASP.NET Core Identity for authentication. The sample demonstrates how a native MAUI app can authenticate against the same identity system as the web app, sharing Razor components across both hosts.What the sample demonstrates
MauiBlazorWeb.Sharedcontains pages (Home, Counter, Weather, NotFound) and services consumed by both the MAUI native app and the ASP.NET Core web app./identity/API endpoints (AddIdentityApiEndpoints) using bearer tokens, withMauiAuthenticationStateProvider,TokenStorage, andHttpClientHelpermanaging the auth flow.USE_SQL_SERVERconditional compilation).What's new in .NET 10
This sample was created by copying the existing
9.0/MauiBlazorWebIdentitysample and upgrading it with all .NET 10 Blazor template features:Passkey support (Identity Schema v3)
AspNetUserPasskeystable viaIdentitySchemaVersions.Version3PasskeySubmit.razor/PasskeySubmit.razor.jsshared component for WebAuthn credential creation/assertionPasskeys.razor— manage page to list/delete passkeysRenamePasskey.razor— manage page to rename a passkeyPasskeyInputModel.cs/PasskeyOperation.cs— supporting modelsLogin.razorupdated with passkey sign-in optionIdentityComponentsEndpointRouteBuilderExtensions.csupdated with passkey assertion/attestation endpointsNotFound page
NotFound.razorin the Shared project (available to both MAUI and Web)UseStatusCodePagesWithReExecute("/not-found")in Program.csNotFoundPageparameter on<Router>in both Web and MAUIRoutes.razorReconnectModal component
ReconnectModal.razor/.razor.css/.razor.js— replaces the oldcomponents-reconnect-modaldiv with a proper Blazor componentApp.razor modernization
<ResourcePreloader />for optimized static asset loading<ImportMap />for ES module import maps@Assets["..."]fingerprinted asset references for cache busting<ReconnectModal />component referenceIdentity page updates
IdentityUserAccessorremoved — replaced byUserManager<ApplicationUser>withRedirectToInvalidUser()patternIdentityRedirectManagerupdated with new redirect helpersIdentityRevalidatingAuthenticationStateProviderupdatedInput = new()→Input = default!withInput ??= new()patternEditContextmodel binding improvementsOther .NET 10 updates
net10.0/net10.0-*10.0.2wwwroot/bootstrap/towwwroot/lib/bootstrap/dist/(full dist from template)app.cssupdated with.form-floating > .form-control:not(:placeholder-shown)stylesMainLayout.razor.css— addedcolor-scheme: light only;NavMenu.razor.css—height→min-heightBlazorDisableThrowNavigationExceptionproperty in Web csprojRedirectToLogincomponent used in WebRoutes.razor(MAUI keeps<Login />)ApplicationDbContextandApplicationUserArchitecture decisions
AddIdentityApiEndpoints(not template'sAddIdentityCore)/identity/REST endpoints for bearer token authAddIdentityCookies()alongsideAddIdentityApiEndpointsAddIdentityApiEndpointsregisters cookie schemes internally; calling both causes duplicate scheme error$([MSBuild]::IsOSPlatform('windows'))dotnet ef migrations add+/p:UseSqlServer=trueNotFound.razorin Shared project@layoutdirective (inherits from router)Preserved from 9.0 (unchanged)
MauiAuthenticationStateProvider,TokenStorage,HttpClientHelper,LoginStatus)RequireAuthorization()AddAdditionalAssembliesfor shared component discoveryProject structure
Testing
AspNetUserPasskeys)