static void

Blazor HttpClient

Install Microsoft.Extensions.Http
learn.microsoft.com (these pages discuss WASM only, no Blazor server)
HttpClient in wasm is actually a facade over javascript FETCH api

Set up DI in Program.cs

This is setting up a named HttpClient (name and the API uri from settings).

var appSettings = builder.Configuration.GetSection("settings").Get<AppSettings>();

//install Microsoft.Extensions.Http

//this adds the IHttpClientFactory service
builder.Services.AddHttpClient(appSettings.ApiName, c =>
{
    //or builder.HostEnvironment.BaseAddress if self-hosted
    c.BaseAddress = new Uri(appSettings.Api);
});
//this add an HttpClient
builder.Services.AddScoped(sp => sp.GetService<IHttpClientFactory>().CreateClient(appSettings.ApiName));

In .net8 you can set up keyed services (here getting the named HttpClient)

builder.Services.AddKeyedScoped(appSettings.ApiName, 
    (sp_) => sp.GetService<IHttpClientFactory>().CreateClient(appSettings.ApiName));

Inject into component

Either as an HttpClient

@page "/useredit/{Id:int}"
@using BlazorApp.Shared
@inject HttpClient Http

<p>Editing user @Id</p>
@if (_user == null)
{
    <p>User not found</p>
}
else
{
    <p>@(_user.Name)</p>
}

@code {

    [Parameter]
    public int Id { getset; }

    private User? _user;

    protected override async Task OnInitializedAsync()
    {
        _user = await Http.GetFromJsonAsync<User>($"User/{Id}");
    }
}

Or as an HttpClientFactory.

@page "/useredit/{Id:int}"
@using BlazorApp.Shared
@inject IHttpClientFactory ClientFactory
@inject IConfiguration Configuration

<p>Editing user @Id</p>
@if (_user == null)
{
    <p>User not found</p>
}
else
{
    <p>@(_user.Name)</p>
}

@code {

    [Parameter]
    public int Id { getset; }

    private User? _user;

    protected override async Task OnInitializedAsync()
    {
        var appSettings = Configuration.GetSection("settings").Get<AppSettings>();
        var client = ClientFactory.CreateClient(appSettings.ApiName);
        _user = await client.GetFromJsonAsync<User>($"User/{Id}");
    }
}

Or use property injection (you have to do this for keyed services in .net8)

[Inject(Key = "key")]
public HttpClient Http { getset; } = default!;

Adding authentication

Install Microsoft.AspNetCore.Components.WebAssembly.Authentication to use PKCE authorization code flow (docs).

There are quite a few steps...

But when that is setup, hooking up your httpclient to always provide the token is simple.

In Program.cs add a MessageHandlerService to the HttpClient

builder.Services.AddHttpClient(appSettings.ApiName, c =>
{
    //or builder.HostEnvironment.BaseAddress if self-hosted
    c.BaseAddress = new Uri(appSettings.Api);
}).AddHttpMessageHandler<BearerAuthorizationMessageHandler>();

And implement an AuthorizationMessageHandler which hooks up the api Urls. Note the library will supply the IAccessTokenProvider

using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

namespace BlazorApp.Client;

/// <summary>
/// A <see cref="DelegatingHandler"/> that attaches access tokens to outgoing <see cref="HttpResponseMessage"/> instances.
/// Access tokens will only be added when the request URI is within one of the base addresses configured using
/// <see cref="ConfigureHandler(IEnumerable{string}, IEnumerable{string}, string)"/>.
/// </summary>
public class BearerAuthorizationMessageHandler : AuthorizationMessageHandler
{
    public BearerAuthorizationMessageHandler(IAccessTokenProvider provider, NavigationManager navigation, IConfiguration config)
        : base(provider, navigation)
    {
        var api = config.GetSection("settings").GetValue<string>("api");
        ConfigureHandler(
            authorizedUrls: new[] { api }
        );
    }
}