
Focus on Blazor WebAssembly (WASM)
Blazor WebAssembly is the most suitable option for creating client-side applications that consume APIs.
Key Points
-
C# in the Browser: The entire .NET runtime and your application are downloaded by the browser as WebAssembly files. C# code runs directly in the browser within a secure sandbox.
-
SPA Architecture: Blazor WASM creates Single Page Applications (SPA), meaning the app loads once and subsequent user interactions dynamically update only the necessary parts of the page, providing a smooth user experience.
-
Razor Components: User interfaces are built using Razor components (
.razor), which combine HTML markup with C# logic (using the@codedirective). -
Open Standards: Building a Blazor app means using Microsoft technology (C#) built upon a totally open and universal foundation (WebAssembly). This ensures your app works on any modern device without depending on proprietary plugins.
Focus on Auth0
-
Auth0 is an Identity Provider that utilizes the OIDC (OpenID Connect) protocol.
-
Blazor WASM is a native OIDC client, and Microsoft provides the
Microsoft.AspNetCore.Components.WebAssembly.Authenticationlibraries to handle it. -
The Blazor application redirects the user to the Auth0 login page (Universal Login), receives the Access Token, and stores it securely.
Blazor WebAssembly Project
Creating the Project in Visual Studio
-
Open Visual Studio and create a New Project.
-
Search for and select the “Blazor WebAssembly App” template (ensure it is not “Blazor Server App”).
-
In the configuration window, under Authentication, choose “None”.
✅ Summary of Recommended Settings
| Option | Status | Notes |
| Progressive Web Application (PWA) | Unchecked | Not necessary for now; reduces complexity. |
| Do not use top-level statements | Unchecked | Uses modern, concise .NET code. |
| Configure for HTTPS | Checked | Essential. Your app must use HTTPS for Auth0 and API calls. |
| Include sample pages | Checked | Useful for base architecture (layout, menu) and quick testing. |
Configuration on Auth0.com
1. Application
In the Auth0 portal, create a new application of type “Single Page Application” . Under the Settings tab:
-
Note down: Domain and Client ID.
-
Enable “Cross-Origin Authentication”.
2. API
In the API section, click + Create API. Complete these fields:
-
Name: A descriptive name (e.g., “My Data Service API”).
-
Identifier: This is the Audience!
The Identifier (Audience) Field
The Identifier (Audience) must be a URI (Uniform Resource Identifier) and usually follows this format:
-
Example Audience:
https://api.yourdomain.com -
Important: It doesn’t have to be a working URL, but it must be a unique URI.
Auth0 Configuration and Dependencies
Packages
To authenticate a Blazor WASM app, use Microsoft’s built-in OIDC support. Install these via NuGet:
-
Microsoft.Authentication.WebAssembly.Msal -
Microsoft.AspNetCore.Components.WebAssembly.Authentication(Version 8.0.1) -
Microsoft.Extensions.Http
Application Configuration
Create appsettings.json in the wwwroot directory to keep configurations separate from code (Best Practice).
{
"Auth0": {
"Domain": "[YOUR-TENANT].auth0.com",
"Authority": "https://[YOUR-TENANT].auth0.com",
"ClientId": "[YOUR-AUTH0-CLIENT-ID]",
"Audience": "https://api.yourdomain.com"
},
"TestWebservice": {
"Address": "localhost:7003"
}
}
Core Application Files
Program.cs
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
// =========================================================
// >>> BASE REGISTRATIONS (Must come before AddOidcAuthentication) <<<
// =========================================================
builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<SignOutSessionStateManager>();
// =========================================================
// =========================================================
// >>> Crucial part for Auth0/OIDC Authentication <<<
// =========================================================
builder.Services.AddOidcAuthentication(options =>
{
// Audience setting (CRUCIAL for calling APIs)
// The Audience must be passed as an additional OIDC parameter
options.ProviderOptions.AdditionalProviderParameters.Add(
"audience",
builder.Configuration["Auth0:Audience"]!
);
// Explicitly assign the Authority
options.ProviderOptions.Authority = builder.Configuration["Auth0:Authority"]!;
// Assign the ClientId
options.ProviderOptions.ClientId = builder.Configuration["Auth0:ClientId"]!;
// Scope Configuration
options.ProviderOptions.DefaultScopes.Clear(); // Remove default scopes
// Add all required scopes, including custom ones:
options.ProviderOptions.DefaultScopes.Add("openid");
options.ProviderOptions.DefaultScopes.Add("profile");
options.ProviderOptions.DefaultScopes.Add("email");
options.ProviderOptions.DefaultScopes.Add("address");
options.ProviderOptions.DefaultScopes.Add("phone");
options.ProviderOptions.DefaultScopes.Add("read:appointments"); // <--- API Scope
});
// =========================================================
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
MainLayout.razor
To display the login status, use the built-in CascadingAuthenticationState component.
In Layout/MainLayout.razor, wrap the content as follows:
@using Microsoft.AspNetCore.Components.Authorization
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<CascadingAuthenticationState>
<main>
<div class="top-row px-4">
<LoginDisplay />
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
</div>
<article class="content px-4">
@Body
</article>
</main>
</CascadingAuthenticationState>
</div>
LoginDisplay.razor
Create a Shared folder and add the LoginDisplay.razor component.
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager
<AuthorizeView>
<Authorized>
Hello, @context.User.Identity?.Name!
<button class="nav-link btn btn-link" @onclick="BeginSignOut">Log out</button>
</Authorized>
<NotAuthorized>
<a href="authentication/login">Log in</a>
</NotAuthorized>
</AuthorizeView>
@code {
[CascadingParameter]
private Task<AuthenticationState>? AuthenticationState { get; set; }
private async Task BeginSignOut()
{
// Redirect user to the Auth0 Logout flow (via Blazor handler)
await SignOutManager.SetSignOutState();
Navigation.NavigateTo("authentication/logout");
}
}
Note: Add the @using YourProjectName.Shared to _Imports.razor.
Authentication Script (index.html)
Add the missing <script> tag in your index.html inside the <body> section, before the Blazor framework script:
<script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
Authentication.razor
Create Pages/Authentication.razor:
@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action" />
@code {
[Parameter]
public string? Action { get; set; }
}
Auth0.com Configuration (Part 2)
Upon launching the app, the “Login” link will appear after a slight delay. Clicking it might trigger “Checking login state…” followed by a “Callback URL mismatch” error.
To fix this, go to your Auth0 Application Settings and add:
-
Allowed Callback URLs:
https://localhost:7004/authentication/login-callback -
Allowed Logout URLs:
https://localhost:7004/authentication/logout-callback
(Ensure the port matches your local project).
Now, Login and Logout should work perfectly!

