asp.net-coreauthorizationhttpclientblazor-webassemblybearer-token

Call endpoint protected with [Authorize] with HttpClient in Blazor wasm


I have a Blazor wasm frontend where I can authenticate myself with an App Registration on Azure. I can successfully login and my identity is correct. In other solution, I have a backend with protected endpoint with [Authorize] attribute.

[ApiController]
[Route("/")]
public class DummyController : ControllerBase
{
    [HttpPost("foo")]
    [Authorize]
    public IActionResult Foo()
    {
        return Ok("Foo");
    }
}

In my program.cs of my backend, I have this lines:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = "https://login.microsoftonline.com/{TENANT-ID}";
        //options.Audience = "http://localhost:8092/";
    });

I try to call this the /foo endpoint from my HttpClient in frontend:

// program.cs
builder.Services.AddMsalAuthentication(options =>
{
    builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
    options.ProviderOptions.LoginMode = "redirect";
    options.ProviderOptions.DefaultAccessTokenScopes
        .Add("https://graph.microsoft.com/User.Read");
});

And the client in frontend where I try to call my endpoint:

public class DummyClient(IAccessTokenProviderAccessor accessTokenProviderAccessor)
{
    private readonly IAccessTokenProviderAccessor _accessTokenProviderAccessor = accessTokenProviderAccessor;

    public async Task<string> FooAsync()
    {
        var tokenResult = await _accessTokenProviderAccessor.TokenProvider.RequestAccessToken();

        if (tokenResult.TryGetToken(out var token))
        {
            _httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + token.Value);
        }

        var client = new HttpClient();
        var response = await _httpClient.GetAsync("http://localhost/foo");
        var text = await response.Content.ReadAsStringAsync();

        return text;
    }
}

But I always get a 401 response, what I'm missing or doing wrong ?


Solution

  • Below are my working codes. With "webapi" template and "blazor WASM standalone template". Both with "microsoft authentication". I think you need set scope for api app registeration in Azure.
    webapi

    builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
             .AddMicrosoftIdentityWebApi(options =>
              {
                  builder.Configuration.Bind("AzureAd", options);
    
                  // Additional options
                  options.TokenValidationParameters = new TokenValidationParameters
                  {
                      ValidAudience = "https://myb2ctest7.onmicrosoft.com/xxxx"
                  };
              }, options => { builder.Configuration.Bind("AzureAd", options); }
             ); 
    

    wasm

        private async Task test()
        {
            string[] scopes = new string[] { "https://myb2ctest7.onmicrosoft.com/xxxx-xxx-xxxx/access_as_user" };
            var tokenResult = await _tokenProvider.RequestAccessToken(new AccessTokenRequestOptions
                {
                    Scopes = scopes
                });
    
            var client = new HttpClient();
            if (tokenResult.TryGetToken(out var token))
            {
    
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token.Value);
                var response = await client.GetAsync("https://localhost:7299/weatherforecast");
    
                if (response.IsSuccessStatusCode)
                {
                    string apiResponse = await response.Content.ReadAsStringAsync();
                    text1 = await response.Content.ReadAsStringAsync();
                }
            }
        }