In my .NET 8 Blazor project, I added the "Individual Account" to manage users. The application has 2 projects.
Server
The server side contains the login part and the controllers/endpoints.
The controllers/endpoints are minimal APIs like this one
public static void MapClientEndpoints (this IEndpointRouteBuilder routes){ var group = routes.MapGroup("/api/Client").WithTags(nameof(Client)); group.MapGet("/", async (HypnoContext db) => { return await db.Client.ToListAsync(); }) .RequireAuthorization() .WithName("GetAllClients") .WithOpenApi();}in order to save in the database. Also, I added the configuration for HttpClient:
builder.Services.AddScoped<AuthenticationStateProvider, PersistingRevalidatingAuthenticationStateProvider>();builder.Services.AddAuthentication(options => { options.DefaultScheme = IdentityConstants.ApplicationScheme; options.DefaultSignInScheme = IdentityConstants.ExternalScheme; }) .AddIdentityCookies();builder.Services.AddIdentityCore<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true) .AddRoles<IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddSignInManager() .AddDefaultTokenProviders();builder.Services .AddScoped(sp => sp .GetRequiredService<IHttpClientFactory>() .CreateClient("ServerAPI")) .AddHttpClient("ServerAPI", (provider, client) => { client.BaseAddress = new Uri(builder. Configuration["FrontendUrl"]); });Client
The client project has all the views. The views call the APIs provided by the server.
In the Program.cs this configuration is added out of the box:
builder.Services.AddSingleton<AuthenticationStateProvider, PersistentAuthenticationStateProvider>();In order to connect to the APIs from the pages, I created a class to group all the calls in a single place. The constructor is this
string baseEndpoint;IHttpClientFactory ClientFactory;HttpClient? httpClient;public ApiService(string baseUrl, IHttpClientFactory clientFactory){ baseEndpoint = baseUrl; ClientFactory = clientFactory; httpClient = ClientFactory.CreateClient("ServerAPI");}Although I log in to the application as a user, the calls to the APIs work only if no authorisation is required in the Minimal API. It is like that the IHttpClientFactory doesn't have the
How can I protect the APIs and use them from the client side?
What I tried
In the Program.cs of the server, I added this code for the HttpClient:
builder.Services.AddScoped<CustomAuthorizationMessageHandler>();builder.Services.AddHttpClient("ServerAPI", client => { client.BaseAddress = new Uri(builder.Configuration["FrontendUrl"]); }) .AddHttpMessageHandler<CustomAuthorizationMessageHandler>();builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("ServerAPI"));The CustomAuthorizationMessageHandler is as follows
public class CustomAuthorizationMessageHandler : AuthorizationMessageHandler{ public CustomAuthorizationMessageHandler(IAccessTokenProvider provider, NavigationManager navigationManager) : base(provider, navigationManager) { ConfigureHandler( authorizedUrls: new[] { "https://localhost:7241" }); }}I'm doing this because I want to make calls to the APIs exposed in the server project protected by the Individual Account. So, in a page
@inject HttpClient httpClientHttpRequestMessage request = new HttpRequestMessage( HttpMethod.Get, "/api/Client");await httpClient.SendAsync(request);When I run the application, I immediately get an error:
System.AggregateException: 'Some services are not able to beconstructed (Error while validating the service descriptor'ServiceType: MyApp.CustomAuthorizationMessageHandlerLifetime: Scoped ImplementationType:MyApp.CustomAuthorizationMessageHandler': Unable to resolveservice for type'Microsoft.AspNetCore.Components.WebAssembly.Authentication.IAccessTokenProvider'while attempting to activate'MyApp.CustomAuthorizationMessageHandler'.)'
Update
I added the configuration of IHttpClientFactory in the client project too.
builder.Services .AddScoped(sp => sp .GetRequiredService<IHttpClientFactory>() .CreateClient("ServerAPI")) .AddHttpClient("ServerAPI", (provider, client) => { client.BaseAddress = new Uri(builder.Configuration["FrontendUrl"]); });But the result has not changed. When from the UI, there is a call to the API, I always get 200 as an HTTP code but the content of the result is a login page.
Just to give you more info, all the calls are in a different project and I reference this project in the client project.



