I am working on an ASP.NET Core 8 MVC application and using Azure AD B2C for authentication management. Below is my appsettings.json configuration:
"AzureAdB2C": {
"Instance": "https://test555.b2clogin.com",
"ClientId": "test555",
"Domain": "test555.onmicrosoft.com",
"SignedOutCallbackPath": "/signout/B2C_1_SignUpSignIn",
"SignUpSignInPolicyId": "B2C_1_SignUpSignIn"
}
Here is how I have configured my Startup.cs
:
public void ConfigureServices(IServiceCollection services)
{
services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAdB2C")
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { Configuration["ProsperityPilot:ProsperityPilotScope"] })
.AddInMemoryTokenCaches();
services.AddTransient<IClaimsTransformation, AddRolesClaimsTransformation>();
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();
services.AddOptions();
services.Configure<OpenIdConnectOptions>(Configuration.GetSection("AzureAdB2C"));
}
Up to this point, everything works fine. I can log in, sign up/sign out using Azure AD B2C, and make API calls obtaining the token like this:
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"));
}
However, I wanted to use IClaimsTransformation to add some claims when a user logs in. I wrote the following method to get a token, but I get the error:
AADSTS50049: Unknown or invalid instance.
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
///...
var token = await GetApplicationTokenAsync();
// search Users by email
var userEmail = principal.Identity.Name;
var user = await _service.GetByEmailAsync(userEmail, token);
///...
return clone;
}
Here is my GetApplicationTokenAsync
:
private async Task<string> GetApplicationTokenAsync()
{
try
{
var clientId = _configuration["AzureAdB2C:ClientId"]; // ClientId of the WebApp
var clientSecret = _configuration["AzureAdB2C:ClientSecret"]; // ClientId of the WebApp
var scope = _configuration["MyApp:MyAppScope"]; // exposed API scope access_as_user
var tenant = _configuration["AzureAdB2C:Domain"];
var policy = _configuration["AzureAdB2C:SignUpSignInPolicyId"];
var tenantName = "mytenant";
var authority = $"https://{tenantName}.b2clogin.com/{tenantName}.onmicrosoft.com/{policy}/v2.0";
var app = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authority))
.Build();
var authResult = await app.AcquireTokenForClient(new[] { scope }).ExecuteAsync();
return authResult.AccessToken;
}
catch (Exception ex)
{
throw;
}
}
Questions:
- What is the correct way to configure the authority to obtain a token in an ASP.NET Core 8 MVC application using Azure AD B2C?
- Do I need to configure a separate DownstreamApi? If so, how should I correctly set it up?
REPO:
I have created this repository to facilitate clear visibility and analysis of the issue I am encountering, allowing for a deeper understanding of the error.
Azure ApiApp
Config:
- API permissions
- Expose an API
- I have 1 Certificate & secret
- Authentication
Azure WebApp
Config:
- Authentication
- I have 1 Certificate & secret
- API permissions
- In the Expose an API section I have nothing