This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
In addition to the client app configuration for server API access, the server API must also allow cross-origin requests (CORS) when the client and the server don't reside at the same base address. For more information on server-side CORS configuration, see the Cross-Origin Resource Sharing (CORS) section later in this article.
In the following LoginDisplay component example, additional parameters are added to the login request:
prompt is set to login: Forces the user to enter their credentials on that request, negating single sign on.
loginHint is set to peter@contoso.com: Pre-fills the username/email address field of the sign-in page for the user to peter@contoso.com. Apps often use this parameter during re-authentication, having already extracted the username from a previous sign in using the preferred_username claim.
In the following example that obtains JSON data via web API, additional parameters are added to the redirect request if an access token isn't available (AccessTokenNotAvailableException is thrown):
prompt is set to login: Forces the user to enter their credentials on that request, negating single sign on.
loginHint is set to peter@contoso.com: Pre-fills the username/email address field of the sign-in page for the user to peter@contoso.com. Apps often use this parameter during re-authentication, having already extracted the username from a previous sign in using the preferred_username claim.
Customize options when using an IAccessTokenProvider
If obtaining a token fails when using an IAccessTokenProvider, manage additional parameters for a new identity provider access token request with the following methods one or more times on a new instance of InteractiveRequestOptions:
In the following example that attempts to obtain an access token for the user, additional parameters are added to the login request if the attempt to obtain a token fails when TryGetToken is called:
prompt is set to login: Forces the user to enter their credentials on that request, negating single sign on.
loginHint is set to peter@contoso.com: Pre-fills the username/email address field of the sign-in page for the user to peter@contoso.com. Apps often use this parameter during re-authentication, having already extracted the username from a previous sign in using the preferred_username claim.
var tokenResult = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions
{
Scopes = new[] { ... }
});
if (!tokenResult.TryGetToken(out var token))
{
tokenResult.InteractionOptions.TryAddAdditionalParameter("prompt", "login");
tokenResult.InteractionOptions.TryAddAdditionalParameter("loginHint",
"peter@contoso.com");
Navigation.NavigateToLogin(accessTokenResult.InteractiveRequestUrl,
accessTokenResult.InteractionOptions);
}
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler
{
public CustomAuthorizationMessageHandler(IAccessTokenProvider provider,
NavigationManager navigation)
: base(provider, navigation)
{
ConfigureHandler(
authorizedUrls: [ "https://api.contoso.com/v1.0" ],
scopes: [ "example.read", "example.write" ]);
}
}
In the preceding code, the scopes example.read and example.write are generic examples not meant to reflect valid scopes for any particular provider.
In the Program file, CustomAuthorizationMessageHandler is registered as a transient service and is configured as the DelegatingHandler for outgoing HttpResponseMessage instances made by a named HttpClient.
builder.Services.AddTransient<CustomAuthorizationMessageHandler>();
builder.Services.AddHttpClient("WebAPI",
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
.AddHttpMessageHandler<CustomAuthorizationMessageHandler>();
Note
In the preceding example, the CustomAuthorizationMessageHandlerDelegatingHandler is registered as a transient service for AddHttpMessageHandler. Transient registration is recommended for IHttpClientFactory, which manages its own DI scopes. For more information, see the following resources:
The configured HttpClient is used to make authorized requests using the try-catch pattern. Where the client is created with CreateClient (Microsoft.Extensions.Http package), the HttpClient is supplied instances that include access tokens when making requests to the server API. If the request URI is a relative URI, as it is in the following example (ExampleAPIMethod), it's combined with the BaseAddress when the client app makes the request:
AuthorizationMessageHandler can be configured with authorized URLs, scopes, and a return URL using the ConfigureHandler method. ConfigureHandler configures the handler to authorize outbound HTTP requests using an access token. The access token is only attached if at least one of the authorized URLs is a base of the request URI (HttpRequestMessage.RequestUri). If the request URI is a relative URI, it's combined with the BaseAddress.
A typed client can be defined that handles all of the HTTP and token acquisition concerns within a single class.
WeatherForecastClient.cs:
using System.Net.Http.Json;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using static {ASSEMBLY NAME}.Data;
public class WeatherForecastClient(HttpClient http)
{
private WeatherForecast[]? forecasts;
public async Task<WeatherForecast[]> GetForecastAsync()
{
try
{
forecasts = await http.GetFromJsonAsync<WeatherForecast[]>(
"WeatherForecast");
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
return forecasts ?? Array.Empty<WeatherForecast>();
}
}
In the preceding example, the WeatherForecast type is a static class that holds weather forecast data. The {ASSEMBLY NAME} placeholder is the app's assembly name (for example, using static BlazorSample.Data;).
using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
...
builder.Services.AddHttpClient<WeatherForecastClient>(
client => client.BaseAddress = new Uri("https://api.contoso.com/v1.0"))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
Unauthenticated or unauthorized web API requests in an app with a secure default client
An app that ordinarily uses a secure default HttpClient can also make unauthenticated or unauthorized web API requests by configuring a named HttpClient.
The controller in the server API, ExampleNoAuthenticationController for the preceding example, isn't marked with the [Authorize] attribute.
The decision whether to use a secure client or an insecure client as the default HttpClient instance is up to the developer. One way to make this decision is to consider the number of authenticated versus unauthenticated endpoints that the app contacts. If the majority of the app's requests are to secure API endpoints, use the authenticated HttpClient instance as the default. Otherwise, register the unauthenticated HttpClient instance as the default.
An alternative approach to using the IHttpClientFactory is to create a typed client for unauthenticated access to anonymous endpoints.
Request additional access tokens
Access tokens can be manually obtained by calling IAccessTokenProvider.RequestAccessToken. In the following example, an additional scope is required by an app for the default HttpClient. The Microsoft Authentication Library (MSAL) example configures the scope with MsalProviderOptions:
A hosted Blazor solution based on the Blazor WebAssembly project template uses the same base address for the client and server apps. The client app's HttpClient.BaseAddress is set to a URI of builder.HostEnvironment.BaseAddress. CORS configuration isn't required in the default configuration of a hosted Blazor solution. Additional client apps that aren't hosted by the server project and don't share the server app's base address do require CORS configuration in the server project.
When a single-page application (SPA) authenticates a user using OpenID Connect (OIDC), the authentication state is maintained locally within the SPA and in the Identity Provider (IP) in the form of a session cookie that's set as a result of the user providing their credentials.
The tokens that the IP emits for the user typically are valid for short periods of time, about one hour normally, so the client app must regularly fetch new tokens. Otherwise, the user would be logged-out after the granted tokens expire. In most cases, OIDC clients are able to provision new tokens without requiring the user to authenticate again thanks to the authentication state or "session" that is kept within the IP.
There are some cases in which the client can't get a token without user interaction, for example, when for some reason the user explicitly logs out from the IP. This scenario occurs if a user visits https://login.microsoftonline.com and logs out. In these scenarios, the app doesn't know immediately that the user has logged out. Any token that the client holds might no longer be valid. Also, the client isn't able to provision a new token without user interaction after the current token expires.
These scenarios aren't specific to token-based authentication. They are part of the nature of SPAs. An SPA using cookies also fails to call a server API if the authentication cookie is removed.
When an app performs API calls to protected resources, you must be aware of the following:
To provision a new access token to call the API, the user might be required to authenticate again.
Even if the client has a token that seems to be valid, the call to the server might fail because the token was revoked by the user.
When the app requests a token, there are two possible outcomes:
The request succeeds, and the app has a valid token.
The request fails, and the app must authenticate the user again to obtain a new token.
When a token request fails, you need to decide whether you want to save any current state before you perform a redirection. Several approaches exist to store state with increasing levels of complexity:
Add a query string parameter and use that as a way to signal the app that it needs to re-hydrate the previously saved state.
Add a query string parameter with a unique identifier to store data in session storage without risking collisions with other items.
Save app state before an authentication operation with session storage
The following example shows how to:
Preserve state before redirecting to the login page.
Recover the previous state after authentication using a query string parameter.
...
@using System.Text.Json
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject IAccessTokenProvider TokenProvider
@inject IJSRuntime JS
@inject NavigationManager Navigation
<EditForm Model="User" OnSubmit="OnSaveAsync">
<label>
First Name:
<InputText @bind-Value="User!.Name" />
</label>
<label>
Last Name:
<InputText @bind-Value="User!.LastName" />
</label>
<button type="submit">Save User</button>
</EditForm>
@code {
public Profile User { get; set; } = new Profile();
protected override async Task OnInitializedAsync()
{
var currentQuery = new Uri(Navigation.Uri).Query;
if (currentQuery.Contains("state=resumeSavingProfile"))
{
var user = await JS.InvokeAsync<string>("sessionStorage.getItem",
"resumeSavingProfile");
if (!string.IsNullOrEmpty(user))
{
User = JsonSerializer.Deserialize<Profile>(user);
}
}
}
public async Task OnSaveAsync()
{
var http = new HttpClient();
http.BaseAddress = new Uri(Navigation.BaseUri);
var resumeUri = Navigation.Uri + $"?state=resumeSavingProfile";
var tokenResult = await TokenProvider.RequestAccessToken(
new AccessTokenRequestOptions
{
ReturnUrl = resumeUri
});
if (tokenResult.TryGetToken(out var token))
{
http.DefaultRequestHeaders.Add("Authorization",
$"Bearer {token.Value}");
await http.PostAsJsonAsync("Save", User);
}
else
{
await JS.InvokeVoidAsync("sessionStorage.setItem",
"resumeSavingProfile", JsonSerializer.Serialize(User));
Navigation.NavigateTo(tokenResult.InteractiveRequestUrl);
}
}
public class Profile
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
}
}
Save app state before an authentication operation with session storage and a state container
During an authentication operation, there are cases where you want to save the app state before the browser is redirected to the IP. This can be the case when you're using a state container and want to restore the state after the authentication succeeds. You can use a custom authentication state object to preserve app-specific state or a reference to it and restore that state after the authentication operation successfully completes. The following example demonstrates the approach.
A state container class is created in the app with properties to hold the app's state values. In the following example, the container is used to maintain the counter value of the default Blazor project template'sCounter component (Counter.razor). Methods for serializing and deserializing the container are based on System.Text.Json.
using System.Text.Json;
public class StateContainer
{
public int CounterValue { get; set; }
public string GetStateForLocalStorage() => JsonSerializer.Serialize(this);
public void SetStateFromLocalStorage(string locallyStoredState)
{
var deserializedState =
JsonSerializer.Deserialize<StateContainer>(locallyStoredState);
CounterValue = deserializedState.CounterValue;
}
}
The Counter component uses the state container to maintain the currentCount value outside of the component:
Create an ApplicationAuthenticationState from RemoteAuthenticationState. Provide an Id property, which serves as an identifier for the locally-stored state.
ApplicationAuthenticationState.cs:
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public class ApplicationAuthenticationState : RemoteAuthenticationState
{
public string? Id { get; set; }
}
The Authentication component (Authentication.razor) saves and restores the app's state using local session storage with the StateContainer serialization and deserialization methods, GetStateForLocalStorage and SetStateFromLocalStorage:
If the requirement calls for completely different paths, set the routes as described previously and render the RemoteAuthenticatorView with an explicit action parameter:
You're allowed to break the UI into different pages if you choose to do so.
Customize the authentication user interface
RemoteAuthenticatorView includes a default set of UI fragments for each authentication state. Each state can be customized by passing in a custom RenderFragment. To customize the displayed text during the initial login process, can change the RemoteAuthenticatorView as follows.
Authentication component (Authentication.razor):
@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action">
<LoggingIn>
You are about to be redirected to https://login.microsoftonline.com.
</LoggingIn>
</RemoteAuthenticatorView>
@code{
[Parameter]
public string? Action { get; set; }
}
@page "/security/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action">
<LoggingIn>
You are about to be redirected to https://login.microsoftonline.com.
</LoggingIn>
</RemoteAuthenticatorView>
@code{
[Parameter]
public string Action { get; set; }
}
The RemoteAuthenticatorView has one fragment that can be used per authentication route shown in the following table.
Route
Fragment
authentication/login
<LoggingIn>
authentication/login-callback
<CompletingLoggingIn>
authentication/login-failed
<LogInFailed>
authentication/logout
<LogOut>
authentication/logout-callback
<CompletingLogOut>
authentication/logout-failed
<LogOutFailed>
authentication/logged-out
<LogOutSucceeded>
authentication/profile
<UserProfile>
authentication/register
<Registering>
Customize the user
Users bound to the app can be customized.
Customize the user with a payload claim
In the following example, the app's authenticated users receive an amr claim for each of the user's authentication methods. The amr claim identifies how the subject of the token was authenticated in Microsoft identity platform v1.0 payload claims. The example uses a custom user account class based on RemoteUserAccount.
Create a class that extends the RemoteUserAccount class. The following example sets the AuthenticationMethod property to the user's array of amr JSON property values. AuthenticationMethod is populated automatically by the framework when the user is authenticated.
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public class CustomUserAccount : RemoteUserAccount
{
[JsonPropertyName("amr")]
public string[]? AuthenticationMethod { get; set; }
}
Create a factory that extends AccountClaimsPrincipalFactory<TAccount> to create claims from the user's authentication methods stored in CustomUserAccount.AuthenticationMethod:
using System.Security.Claims;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
public class CustomAccountFactory(NavigationManager navigation,
IAccessTokenProviderAccessor accessor)
: AccountClaimsPrincipalFactory<CustomUserAccount>(accessor)
{
public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
CustomUserAccount account, RemoteAuthenticationUserOptions options)
{
var initialUser = await base.CreateUserAsync(account, options);
if (initialUser.Identity != null && initialUser.Identity.IsAuthenticated)
{
var userIdentity = (ClaimsIdentity)initialUser.Identity;
if (account.AuthenticationMethod is not null)
{
foreach (var value in account.AuthenticationMethod)
{
userIdentity.AddClaim(new Claim("amr", value));
}
}
}
return initialUser;
}
}
Register the CustomAccountFactory for the authentication provider in use. Any of the following registrations are valid:
Prerendering content that requires authentication and authorization isn't currently supported. After following the guidance in one of the Blazor WebAssembly security app topics, use the following instructions to create an app that:
Prerenders paths for which authorization isn't required.
Doesn't prerender paths for which authorization is required.
For the Client project's the Program file, factor common service registrations into a separate method (for example, create a ConfigureCommonServices method in the Client project). Common services are those that the developer registers for use by both the client and server projects.
public static void ConfigureCommonServices(IServiceCollection services)
{
services.Add...;
}
In the Server project's the Program file, register the following additional services and call ConfigureCommonServices:
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
...
builder.Services.AddRazorPages();
builder.Services.TryAddScoped<AuthenticationStateProvider,
ServerAuthenticationStateProvider>();
Client.Program.ConfigureCommonServices(services);
In the Server project's Startup.ConfigureServices method, register the following additional services and call ConfigureCommonServices:
using Microsoft.AspNetCore.Components.Authorization;
using Microsoft.AspNetCore.Components.Server;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
public void ConfigureServices(IServiceCollection services)
{
...
services.AddRazorPages();
services.AddScoped<AuthenticationStateProvider,
ServerAuthenticationStateProvider>();
services.AddScoped<SignOutSessionStateManager>();
Client.Program.ConfigureCommonServices(services);
}
The {CLIENT APP ASSEMBLY NAME} placeholder is the client app's assembly name (for example BlazorSample.Client).
The conditional check for the /authentication path segment:
Avoids prerendering (render-mode="WebAssembly") for authentication paths.
Prerenders (render-mode="WebAssemblyPrerendered") for non-authentication paths.
Options for hosted apps and third-party login providers
When authenticating and authorizing a hosted Blazor WebAssembly app with a third-party provider, there are several options available for authenticating the user. Which one you choose depends on your scenario.
Authenticate users with a third-party provider and call protected APIs on the host server and the third party
Configure Identity with a third-party login provider. Obtain the tokens required for third-party API access and store them.
When a user logs in, Identity collects access and refresh tokens as part of the authentication process. At that point, there are a couple of approaches available for making API calls to third-party APIs.
Use a server access token to retrieve the third-party access token
Use the access token generated on the server to retrieve the third-party access token from a server API endpoint. From there, use the third-party access token to call third-party API resources directly from Identity on the client.
We don't recommend this approach. This approach requires treating the third-party access token as if it were generated for a public client. In OAuth terms, the public app doesn't have a client secret because it can't be trusted to store secrets safely, and the access token is produced for a confidential client. A confidential client is a client that has a client secret and is assumed to be able to safely store secrets.
The third-party access token might be granted additional scopes to perform sensitive operations based on the fact that the third-party emitted the token for a more trusted client.
Similarly, refresh tokens shouldn't be issued to a client that isn't trusted, as doing so gives the client unlimited access unless other restrictions are put into place.
Make API calls from the client to the server API in order to call third-party APIs
Make an API call from the client to the server API. From the server, retrieve the access token for the third-party API resource and issue whatever call is necessary.
We recommend this approach. While this approach requires an extra network hop through the server to call a third-party API, it ultimately results in a safer experience:
The server can store refresh tokens and ensure that the app doesn't lose access to third-party resources.
The app can't leak access tokens from the server that might contain more sensitive permissions.
Use OpenID Connect (OIDC) v2.0 endpoints
The authentication library and Blazor project templates use OpenID Connect (OIDC) v1.0 endpoints. To use a v2.0 endpoint, configure the JWT Bearer JwtBearerOptions.Authority option. In the following example, ME-ID is configured for v2.0 by appending a v2.0 segment to the Authority property:
If tacking on a segment to the authority isn't appropriate for the app's OIDC provider, such as with non-ME-ID providers, set the Authority property directly. Either set the property in JwtBearerOptions or in the app settings file (appsettings.json) with the Authority key.
The list of claims in the ID token changes for v2.0 endpoints. Microsoft documentation on the changes has been retired, but guidance on the claims in an ID token is available in the ID token claims reference.
Register gRPC services for the app's message handler. The following example configures the app's authorization message handler to use the GreeterClient service from the gRPC tutorial (the Program file).
Note
Prerendering is enabled by default in Blazor Web Apps, so you must account for the component rendering first from the server and then from the client. Any prerendered state should flow to the client so that it can be reused. For more information, see Prerender ASP.NET Core Razor components.
using System.Net.Http;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Grpc.Net.Client;
using Grpc.Net.Client.Web;
...
builder.Services.AddScoped(sp =>
{
var baseAddressMessageHandler =
sp.GetRequiredService<BaseAddressAuthorizationMessageHandler>();
baseAddressMessageHandler.InnerHandler = new HttpClientHandler();
var grpcWebHandler =
new GrpcWebHandler(GrpcWebMode.GrpcWeb, baseAddressMessageHandler);
var channel = GrpcChannel.ForAddress(builder.HostEnvironment.BaseAddress,
new GrpcChannelOptions { HttpHandler = grpcWebHandler });
return new Greeter.GreeterClient(channel);
});
A component in the client app can make gRPC calls using the gRPC client (Grpc.razor):
@page "/grpc"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize]
@inject Greeter.GreeterClient GreeterClient
<h1>Invoke gRPC service</h1>
<p>
<input @bind="name" placeholder="Type your name" />
<button @onclick="GetGreeting" class="btn btn-primary">Call gRPC service</button>
</p>
Server response: <strong>@serverResponse</strong>
@code {
private string name = "Bert";
private string? serverResponse;
private async Task GetGreeting()
{
try
{
var request = new HelloRequest { Name = name };
var reply = await GreeterClient.SayHelloAsync(request);
serverResponse = reply.Message;
}
catch (Grpc.Core.RpcException ex)
when (ex.Status.DebugException is
AccessTokenNotAvailableException tokenEx)
{
tokenEx.Redirect();
}
}
}
To use the Status.DebugException property, use Grpc.Net.Client version 2.30.0 or later.
// .NET makes calls to an AuthenticationService object in the Window.
declare global {
interface Window { AuthenticationService: AuthenticationService }
}
export interface AuthenticationService {
// Init is called to initialize the AuthenticationService.
public static init(settings: UserManagerSettings & AuthorizeServiceSettings, logger: any) : Promise<void>;
// Gets the currently authenticated user.
public static getUser() : Promise<{[key: string] : string }>;
// Tries to get an access token silently.
public static getAccessToken(options: AccessTokenRequestOptions) : Promise<AccessTokenResult>;
// Tries to sign in the user or get an access token interactively.
public static signIn(context: AuthenticationContext) : Promise<AuthenticationResult>;
// Handles the sign-in process when a redirect is used.
public static async completeSignIn(url: string) : Promise<AuthenticationResult>;
// Signs the user out.
public static signOut(context: AuthenticationContext) : Promise<AuthenticationResult>;
// Handles the signout callback when a redirect is used.
public static async completeSignOut(url: string) : Promise<AuthenticationResult>;
}
// The rest of these interfaces match their C# definitions.
export interface AccessTokenRequestOptions {
scopes: string[];
returnUrl: string;
}
export interface AccessTokenResult {
status: AccessTokenResultStatus;
token?: AccessToken;
}
export interface AccessToken {
value: string;
expires: Date;
grantedScopes: string[];
}
export enum AccessTokenResultStatus {
Success = 'Success',
RequiresRedirect = 'RequiresRedirect'
}
export enum AuthenticationResultStatus {
Redirect = 'Redirect',
Success = 'Success',
Failure = 'Failure',
OperationCompleted = 'OperationCompleted'
};
export interface AuthenticationResult {
status: AuthenticationResultStatus;
state?: unknown;
message?: string;
}
export interface AuthenticationContext {
state?: unknown;
interactiveRequest: InteractiveAuthenticationRequest;
}
export interface InteractiveAuthenticationRequest {
scopes?: string[];
additionalRequestParameters?: { [key: string]: any };
};
You can import the library by removing the original <script> tag and adding a <script> tag that loads the custom library. The following example demonstrates replacing the default <script> tag with one that loads a library named CustomAuthenticationService.js from the wwwroot/js folder.
In wwwroot/index.html before the Blazor script (_framework/blazor.webassembly.js) inside the closing </body> tag:
Documentation links to .NET reference source usually load the repository's default branch, which represents the current development for the next release of .NET. To select a tag for a specific release, use the Switch branches or tags dropdown list. For more information, see How to select a version tag of ASP.NET Core source code (dotnet/AspNetCore.Docs #26205).
Replace the Microsoft Authentication Library for JavaScript (MSAL.js)
Confirm the system has the latest developer .NET SDK or obtain and install the latest developer SDK from .NET Core SDK: Installers and Binaries. Configuration of internal NuGet feeds isn't required for this scenario.
Open the src/Components/WebAssembly/Authentication.Msal/src/Interop/package.json file and set the desired version of @azure/msal-browser. For a list of released versions, visit the @azure/msal-browser npm website and select the Versions tab.
Build the Authentication.Msal project in the src/Components/WebAssembly/Authentication.Msal/src folder with the yarn build command in a command shell.
Copy the AuthenticationService.js file and compressed versions (.br/.gz) of the file, if produced, from the Interop/dist/Release folder into the app's publish/wwwroot/_content/Microsoft.Authentication.WebAssembly.Msal folder in the app's published assets.
Pass custom provider options
Define a class for passing the data to the underlying JavaScript library.
Important
The class's structure must match what the library expects when the JSON is serialized with System.Text.Json.
The following example demonstrates a ProviderOptions class with JsonPropertyName attributes matching a hypothetical custom provider library's expectations:
public class ProviderOptions
{
public string? Authority { get; set; }
public string? MetadataUrl { get; set; }
[JsonPropertyName("client_id")]
public string? ClientId { get; set; }
public IList<string> DefaultScopes { get; set; } = [ "openid", "profile" ];
[JsonPropertyName("redirect_uri")]
public string? RedirectUri { get; set; }
[JsonPropertyName("post_logout_redirect_uri")]
public string? PostLogoutRedirectUri { get; set; }
[JsonPropertyName("response_type")]
public string? ResponseType { get; set; }
[JsonPropertyName("response_mode")]
public string? ResponseMode { get; set; }
}
Register the provider options within the DI system and configure the appropriate values:
Uri.TryCreate(
$"{builder.HostEnvironment.BaseAddress}authentication/login-callback",
UriKind.Absolute, out var redirectUri);
options.RedirectUri = redirectUri;
The source for this content can be found on GitHub, where you can also create and review issues and pull requests. For more information, see our contributor guide.
ASP.NET Core feedback
ASP.NET Core is an open source project. Select a link to provide feedback:
Publish an Angular, React, Svelte, or Vue JavaScript app with API and authentication using Azure Static Web Apps and Azure Functions. Deploy your code from GitHub to a staging site using preview URLs.