Getting error Bearer error="invalid_token" while calling Web API using C# code

Pranav 0 Reputation points
2024-08-02T18:15:26.8333333+00:00

I was learning to authenticate API using Azure AD authentication this is the code which I configured on MVC side

public async Task<IEnumerable<Todo>> GetAsync()
{
    await PrepareAuthenticatedClient();

    var response = await _httpClient.GetAsync($"{ _TodoListBaseAddress}/api/todolist");
    if (response.StatusCode == HttpStatusCode.OK)
    {
        var content = await response.Content.ReadAsStringAsync();
        IEnumerable<Todo> todolist = JsonConvert.DeserializeObject<IEnumerable<Todo>>(content);

        return todolist;
    }

    throw new HttpRequestException($"Invalid status code in the HttpResponseMessage: {response.StatusCode}.");
}
private async Task PrepareAuthenticatedClient()
{
   ` var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { _TodoListScope });
    Debug.WriteLine($"access token-{accessToken}");
        _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
    _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));`
}

MVC appsetting.json file{ "AzureAdB2C": { "Instance": "https://login.microsoftonline.com/", "Domain": "xxxx.com", "TenantId": "4d5c2d64-35d8-4200-805e-xxxxxx11e", "SignedOutCallbackPath": "/signout", "ClientSecret": "MMA8Q~T~KwXpSqDscijieKycv7Zxxxxxxxxxt", "ClientId": "c8db825e-be17-4943-b2e5-caxxxxx5" }, "TodoList": { "TodoListScope": "tasks.read", "TodoListBaseAddress": "https://localhost:44332" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" }
WEB API Startup file



Web API appsetting.json 
This is the repo which I used to get code online 
I want that API should accept token generated from Azure AD user . I tried to configure details which I found online but API does not accept bearer token
Developer technologies ASP.NET ASP.NET Core
Developer technologies C#
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Bruce (SqlWork.com) 77,686 Reputation points Volunteer Moderator
    2024-08-02T21:04:24.85+00:00

    You don’t specify the version of .net nor the configuration of authentication. GetAccessTokenForUserAsync() is used with oauth cookie authentication, and requires a cache to store the jwt tokens, as the cookies only have the cookie principle. Also typically you would register the mvc app and the api app. The api app configuration would include expose the api to clientid of the mvc app. See docs:

    https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-web-api-aspnet-core-protect-api

    0 comments No comments

  2. Anonymous
    2024-08-05T07:55:50.5066667+00:00

    Hi, From your code, I think you are looking for MVC front-end using HttpClient to access WebApi back-end with Azure B2C authentication. You could try following steps.

    In Azure B2C, register a "webapi" application. expose the api with scope of "access_as_user" ,Note down the full scope string.

    User's image

    Create a webapi with "microsoft identity platfrom" template, fill the appsetting with the registered info

      "AzureAd": {
        "Instance": "https://login.microsoftonline.com/",
        "Domain": "xxx.onmicrosoft.com",
        "TenantId": "xxx",
        "ClientId": "xxx",
        "CallbackPath": "/signin-oidc"
      }
    

    Change the program.cs like following to add B2C audience:

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

    Next, register a MVC application in Azure B2C, find and add api permissions to the "access_as_user" we set up above.

    User's image

    Create a MVC with "microsoft identity platform" template and modify the appsettings, add the scopes with the scope string we note down above.

      "AzureAd": {
        "Instance": "https://login.microsoftonline.com/",
        "Domain": "xxx.onmicrosoft.com",
        "TenantId": "xxx",
        "ClientId": "xxx",
        "ClientSecret": "xxx",
        "CallbackPath": "/signin-oidc",
        "Scopes": "https://xxx.onmicrosoft.com/{webapi-clientID}/access_as_user"
      },
    

    Modify the program.cs like below

    builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
        .EnableTokenAcquisitionToCallDownstreamApi()
        .AddInMemoryTokenCaches();
    

    Then in the MVC project you could access back-end api using following code.

                string[] scopes = new string[] { "https://myb2ctest7.onmicrosoft.com/{webapi-clientID}/access_as_user" };
                string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
                _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
                var response = await _httpClient.GetAsync("https://localhost:7299/weatherforecast");
    

    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".  Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.