I have 2 applications, WebApi(ASP.NET Core Web API) and WebApp(Vite.js), they will be all hosted in Azure.
I would like to use Azure AD B2C to secure the endpoints in the WebApi project, the grant type should be client_credentials, so that when the WebApp call the WebApi endpoints, it calls the Auth endpoint first to get the access token and then use the access token in its following request header.
What I have done so far:
- Register Web API in Azure AD B2C:
and generate a client secret for Web API.
Also exposed the API by adding the scopes

Added the Microsoft Identity Web library to simplify Azure AD B2C authentication. Initiated the authentication libraries in your startup class. Added the necessary app settings for Azure AD B2C in your appsettings.json file.
and generate a client secret for the Web APP.
Implement Application-to-Application Protection: and configured the permission scope for the WebApp

Set Up Federation Between Azure B2C and Azure AD Single Tenant: Federate your Azure B2C identity provider with the Azure AD single tenant App registration.

The Client ID is the frontend Web App Client ID.
The User ID is the Subject ID I got from decoding the JWT token which is the Backend Web API Subject ID.
Now I would like to test calling the endpoints in my local dev environment by using Swagger UI.
The code:
Prohgram.cs
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
using Microsoft.OpenApi.Models;
using Serilog;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
builder.Host.UseSerilog();
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c => {
c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
{
Title = "JWTToken_Auth_API",
Version = " v1"
});
c.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme()
{
Name = "Authorization",
Type = Microsoft.OpenApi.Models.SecuritySchemeType.ApiKey,
Scheme = "Bearer",
BearerFormat = "JWT",
In = Microsoft.OpenApi.Models.ParameterLocation.Header,
Description = "Wahaha",
OpenIdConnectUrl= new Uri("https://mycomp.b2clogin.com/mycomp.onmicrosoft.com/B2C_1_SignInAPI/v2.0/.well-known/openid-configuration")
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement {
{
new OpenApiSecurityScheme {
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] {}
}
});
});
var app = builder.Build();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.Run();
ADB2CAuthController.cs
using Microsoft.AspNetCore.Mvc;
namespace MyCompBackend.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ADB2CAuthController : ControllerBase
{
[HttpPost]
public async Task<string> Post()
{
var token = await AuthGetter.GetJWTTokenAsync();
return token;
}
}
}
WeatherForecastController.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Web.Resource;
namespace MyCompBackend.Controllers
{
[Authorize]//(Policy = "WebAppPolicy")
//(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
[Route("[controller]")]
[RequiredScope(RequiredScopesConfigurationKey = "AzureAd:Scopes")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}
appsettings.json and appsettings.Development.json, they are same for now
{
"AzureAd": {
"Instance": "https://mycomp.b2clogin.com/",
"Domain": "mycomp.onmicrosoft.com",
"TenantId": "a15e2b5d-affa-4fdc-a947-xxxxxxxxxxxx",
"ClientId": "49f6d1e2-943b-4b88-bfa1-xxxxxxxxxxxx",
"CallbackPath": "/signin-oidc",
"Scopes": "access_api_only",
"SignUpSignInPolicyId": "B2C_1_susi",
"SingInAPIPolicyId": "B2C_1_SignInAPI",
"SignedOutCallbackPath": "/signout/B2C_1_susi",
"ResetPasswordPolicyId": "b2c_1_reset",
"EditProfilePolicyId": "b2c_1_edit_profile",
"EnablePiiLogging": true,
"WebApiClientSecret": "xxxxxxxxxxxx",
"WebAppClientSecret": "xxxxxxxxxxxx"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Where I am:
I am able to call the Auth endpoint and retrieve a access token,
[
]
I then use the Authorize button at the top right corner and put in the value of the token like: Bearer
[
]
Then I scroll to the Weather Forecast endpoint and try to test it:
[
]
But as you can see that it always return 401.
(https://i.stack.imgur.com/owOhC.png) (https://i.stack.imgur.com/eDCXH.png) (https://i.stack.imgur.com/KJPhV.png)
I have tried to Google and tried so many different ways.
What could be the issues? And how to fix them?


