MAUI Auth and Secure Storage
Use this skill when a MAUI app needs sign-in, token handling, secure local
secrets, or auth state shared between native pages and Blazor Hybrid UI.
Workflow
- Inspect target frameworks, package references,
MauiProgram.cs, platform
manifests/plists, and existing auth abstractions.
- Choose the auth primitive:
- Use
WebAuthenticator for provider-neutral OAuth/OIDC browser redirects.
- Use MSAL.NET for Microsoft Entra ID, account selection, silent token
acquisition, and broker integration.
- Register redirect URIs in both the identity provider and platform app
configuration. The scheme/host must match exactly.
- Keep auth behind an injected service such as
IAuthService; do not put token
acquisition logic directly in pages or ViewModels.
- Let MSAL own its token cache when using MSAL. Use
SecureStorage for
app-owned secrets, small encrypted values, and non-MSAL providers only when
the provider requires app-managed refresh token storage.
- Handle cancellation, denied consent, and expired sessions as first-class UI
states instead of treating all auth failures as crashes.
- For Blazor Hybrid, hand native auth state into scoped services or an
AuthenticationStateProvider; do not rely on browser cookies or local
storage as the source of truth.
WebAuthenticator Pattern
var result = await WebAuthenticator.Default.AuthenticateAsync(
new WebAuthenticatorOptions
{
Url = authorizeUri,
CallbackUrl = new Uri("myapp://auth")
});
if (result.Properties.TryGetValue("error", out var error))
{
throw new InvalidOperationException($"Authentication failed: {error}");
}
result.Properties.TryGetValue("code", out var code);
Build the authorize URI with PKCE when the provider supports it. Exchange the
authorization code through a secure backend or a provider-supported public
client flow; do not embed client secrets in the app package.
MSAL.NET Pattern
builder.Services.AddSingleton<IAuthService, MsalAuthService>();
For MSAL:
- Configure redirect URIs in the Entra app registration and the platform app.
- Build the public client with an explicit redirect URI, for example
.WithRedirectUri("msal{client-id}://auth") when using the default MAUI MSAL
public-client redirect pattern. Broker-capable apps must use the broker
redirect URI expected by the platform and app registration, often referred to
as the BrokerRedirectUri in MSAL setup guidance.
- Prefer
AcquireTokenSilent before interactive auth.
- Use MSAL's platform token cache for MAUI mobile targets and verify persistence
on each target platform. Add custom token-cache serialization only for
desktop, unsupported, or intentionally custom cache scenarios.
- Use interactive auth only when there is no cached account, consent is needed,
or silent acquisition returns a UI-required result.
- Inspect
MsalUiRequiredException.Classification, error codes, and claims
before blindly retrying interactive auth. Conditional Access, compliant-device,
or Intune protection-policy failures may require compliance UX or Intune MAM
integration, not another generic prompt.
- Opt into brokers only when the app registration, redirect URI, and platform
setup are broker-ready.
- Store account identifiers or display names if needed; do not duplicate MSAL
access or refresh tokens into
Preferences.
- On logout, call
GetAccountsAsync() and RemoveAsync(account) for cached
MSAL accounts before clearing app-owned auth state, so the next
AcquireTokenSilent cannot return the signed-out user's tokens.
Platform Redirect Checklist
| Platform |
Check |
| Android |
For WebAuthenticator, add an Android activity subclass that inherits Microsoft.Maui.Authentication.WebAuthenticatorCallbackActivity and has an IntentFilter for the callback scheme/host. Use MAUI namespaces, not Xamarin.Auth or Xamarin.Essentials callback types. For MSAL broker flows, use the broker-compatible redirect URI and signature hash expected by the app registration. |
| iOS/Mac Catalyst |
Add CFBundleURLTypes for the callback scheme. For MSAL broker flows, add LSApplicationQueriesSchemes entries such as msauthv2 and msauthv3 so MSAL can detect the broker, and match the redirect URI scheme configured in the app registration. |
| Windows |
Register the custom protocol in the package manifest or app identity configuration used by the target. |
SecureStorage Guardrails
- Use
SecureStorage.Default.GetAsync, SetAsync, and Remove for small
secrets only.
- Treat missing values as normal after reinstall, backup restore, device lock
changes, or secure store reset.
- On Mac Catalyst, configure Keychain Sharing in
Platforms/MacCatalyst/Entitlements.plist; secure storage calls fail without
the required keychain entitlement.
- On iOS and Mac Catalyst, app extensions cannot read the host app's secure
values unless a shared keychain access group is configured in both host and
extension entitlements.
- Store expiration metadata with app-owned tokens and refresh before use.
- Prefer a backend token exchange when a provider requires confidential client
secrets.
- Never log tokens, authorization codes,
id_token values, refresh tokens, or
full callback URLs.
Blazor Hybrid Auth Handoff
- Register the native auth/session service in MAUI DI and consume it from Razor
components through DI.
- Implement a custom
AuthenticationStateProvider when Razor components need
[Authorize] or AuthorizeView.
- Attach bearer tokens through a typed
HttpClient handler that asks the native
auth service for a fresh access token.
- Clear MSAL accounts with
RemoveAsync, app-owned SecureStorage values, and
Blazor auth state on logout.
Validation Checklist
- Redirect URI values match across provider registration and platform files.
- Auth flows use PKCE or MSAL public-client patterns and contain no client
secrets.
- Silent token acquisition is attempted before interactive MSAL prompts.
- Logout clears MSAL cached accounts with
RemoveAsync and invalidates Blazor
auth state when used.
- Secure values are stored only in
SecureStorage or the library-owned cache.
- Blazor Hybrid components receive auth state through DI, not browser-only
storage.
1---2name: maui-auth-secure-storage3description: Implement MAUI auth and secure storage. USE FOR: WebAuthenticator/MSAL, OAuth/OIDC redirects, Entra ID, callback URIs, Android intent filters, `CFBundleURLTypes`, token cache cleanup, SecureStorage, logout, Blazor Hybrid auth handoff. DO NOT USE FOR: architecture, API retries/offline data, UI debugging.4---56# MAUI Auth and Secure Storage78Use this skill when a MAUI app needs sign-in, token handling, secure local9secrets, or auth state shared between native pages and Blazor Hybrid UI.1011## Workflow12131. Inspect target frameworks, package references, `MauiProgram.cs`, platform14 manifests/plists, and existing auth abstractions.152. Choose the auth primitive:16 - Use `WebAuthenticator` for provider-neutral OAuth/OIDC browser redirects.17 - Use MSAL.NET for Microsoft Entra ID, account selection, silent token18 acquisition, and broker integration.193. Register redirect URIs in both the identity provider and platform app20 configuration. The scheme/host must match exactly.214. Keep auth behind an injected service such as `IAuthService`; do not put token22 acquisition logic directly in pages or ViewModels.235. Let MSAL own its token cache when using MSAL. Use `SecureStorage` for24 app-owned secrets, small encrypted values, and non-MSAL providers only when25 the provider requires app-managed refresh token storage.266. Handle cancellation, denied consent, and expired sessions as first-class UI27 states instead of treating all auth failures as crashes.287. For Blazor Hybrid, hand native auth state into scoped services or an29 `AuthenticationStateProvider`; do not rely on browser cookies or local30 storage as the source of truth.3132## WebAuthenticator Pattern3334```csharp35var result = await WebAuthenticator.Default.AuthenticateAsync(36 new WebAuthenticatorOptions37 {38 Url = authorizeUri,39 CallbackUrl = new Uri("myapp://auth")40 });4142if (result.Properties.TryGetValue("error", out var error))43{44 throw new InvalidOperationException($"Authentication failed: {error}");45}4647result.Properties.TryGetValue("code", out var code);48```4950Build the authorize URI with PKCE when the provider supports it. Exchange the51authorization code through a secure backend or a provider-supported public52client flow; do not embed client secrets in the app package.5354## MSAL.NET Pattern5556```csharp57builder.Services.AddSingleton<IAuthService, MsalAuthService>();58```5960For MSAL:6162- Configure redirect URIs in the Entra app registration and the platform app.63- Build the public client with an explicit redirect URI, for example64 `.WithRedirectUri("msal{client-id}://auth")` when using the default MAUI MSAL65 public-client redirect pattern. Broker-capable apps must use the broker66 redirect URI expected by the platform and app registration, often referred to67 as the `BrokerRedirectUri` in MSAL setup guidance.68- Prefer `AcquireTokenSilent` before interactive auth.69- Use MSAL's platform token cache for MAUI mobile targets and verify persistence70 on each target platform. Add custom token-cache serialization only for71 desktop, unsupported, or intentionally custom cache scenarios.72- Use interactive auth only when there is no cached account, consent is needed,73 or silent acquisition returns a UI-required result.74- Inspect `MsalUiRequiredException.Classification`, error codes, and claims75 before blindly retrying interactive auth. Conditional Access, compliant-device,76 or Intune protection-policy failures may require compliance UX or Intune MAM77 integration, not another generic prompt.78- Opt into brokers only when the app registration, redirect URI, and platform79 setup are broker-ready.80- Store account identifiers or display names if needed; do not duplicate MSAL81 access or refresh tokens into `Preferences`.82- On logout, call `GetAccountsAsync()` and `RemoveAsync(account)` for cached83 MSAL accounts before clearing app-owned auth state, so the next84 `AcquireTokenSilent` cannot return the signed-out user's tokens.8586## Platform Redirect Checklist8788| Platform | Check |89| --- | --- |90| Android | For `WebAuthenticator`, add an Android activity subclass that inherits `Microsoft.Maui.Authentication.WebAuthenticatorCallbackActivity` and has an `IntentFilter` for the callback scheme/host. Use MAUI namespaces, not Xamarin.Auth or Xamarin.Essentials callback types. For MSAL broker flows, use the broker-compatible redirect URI and signature hash expected by the app registration. |91| iOS/Mac Catalyst | Add `CFBundleURLTypes` for the callback scheme. For MSAL broker flows, add `LSApplicationQueriesSchemes` entries such as `msauthv2` and `msauthv3` so MSAL can detect the broker, and match the redirect URI scheme configured in the app registration. |92| Windows | Register the custom protocol in the package manifest or app identity configuration used by the target. |9394## SecureStorage Guardrails9596- Use `SecureStorage.Default.GetAsync`, `SetAsync`, and `Remove` for small97 secrets only.98- Treat missing values as normal after reinstall, backup restore, device lock99 changes, or secure store reset.100- On Mac Catalyst, configure Keychain Sharing in101 `Platforms/MacCatalyst/Entitlements.plist`; secure storage calls fail without102 the required keychain entitlement.103- On iOS and Mac Catalyst, app extensions cannot read the host app's secure104 values unless a shared keychain access group is configured in both host and105 extension entitlements.106- Store expiration metadata with app-owned tokens and refresh before use.107- Prefer a backend token exchange when a provider requires confidential client108 secrets.109- Never log tokens, authorization codes, `id_token` values, refresh tokens, or110 full callback URLs.111112## Blazor Hybrid Auth Handoff113114- Register the native auth/session service in MAUI DI and consume it from Razor115 components through DI.116- Implement a custom `AuthenticationStateProvider` when Razor components need117 `[Authorize]` or `AuthorizeView`.118- Attach bearer tokens through a typed `HttpClient` handler that asks the native119 auth service for a fresh access token.120- Clear MSAL accounts with `RemoveAsync`, app-owned `SecureStorage` values, and121 Blazor auth state on logout.122123## Validation Checklist124125- Redirect URI values match across provider registration and platform files.126- Auth flows use PKCE or MSAL public-client patterns and contain no client127 secrets.128- Silent token acquisition is attempted before interactive MSAL prompts.129- Logout clears MSAL cached accounts with `RemoveAsync` and invalidates Blazor130 auth state when used.131- Secure values are stored only in `SecureStorage` or the library-owned cache.132- Blazor Hybrid components receive auth state through DI, not browser-only133 storage.