In my Blazor app, I need to be able to send HTTP requests to my API service and I use Refit for this. That way I can use Refitter to generate my API class and save a lot of time, and I can also use the same class to make calls no matter if I am on Server or WebAssembly (very useful if you are using Auto render mode!)
First, create an AuthBearerTokenFactory:
public static class AuthBearerTokenFactory
{
private static Func<HttpRequestMessage, CancellationToken, Task<string>>? _getBearerTokenAsyncFunc;
/// <summary>
/// Provide a delegate that returns a bearer token to use for authorization
/// </summary>
public static void SetBearerTokenGetterFunc(Func<HttpRequestMessage, CancellationToken, Task<string>> getBearerTokenAsyncFunc)
=> _getBearerTokenAsyncFunc = getBearerTokenAsyncFunc;
public static Task<string> GetBearerTokenAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (_getBearerTokenAsyncFunc is null)
throw new InvalidOperationException("Must set Bearer Token Func before using it!");
return _getBearerTokenAsyncFunc!(request, cancellationToken);
}
}
Then register the SetBearerTokenGetterFunc in your program after app = builder.Build()
AuthBearerTokenFactory.SetBearerTokenGetterFunc(async (request, cancellationToken) =>
{
var httpContextAccessor = app.Services.GetRequiredService<IHttpContextAccessor>();
var configuration = app.Services.GetRequiredService<IConfiguration>();
var scopedServices = httpContextAccessor.HttpContext?.RequestServices ?? throw new Exception("HttpContext not set!");
var tokenAcquisition = scopedServices.GetRequiredService<ITokenAcquisition>();
var scopes = configuration.GetSection("SCOPES_HERE").Get<IEnumerable<string>>() ?? throw new Exception("Scopes are not set in app config!");
var httpContext = httpContextAccessor.HttpContext ?? throw new Exception("No HttpContext available!");
return await tokenAcquisition.GetAccessTokenForUserAsync(scopes, user: httpContext.User);
});
Then when registering Refit, set the auth header getter to AuthBearerTokenFactory.GetBearerTokenAsync
And now you should be able to authenticate!
Note: I have had some issues with Hot Reload causing the HTTP context to not be set, but this only seems to occur when developing, and only sometimes, so I don’t consider it a big deal.
Leave a Reply