I'm using an Azure ADB2C sign in flow that calls an Azure function to set custom claims, in my case userId, prior to the authorization ticket being set. My Blazor app consumes my token correctly and I can see my custom claim inside my Identity user when working in the app. When I attempt to call my API downstream I use ITokenAcquistion GetAccessTokenForUserAsync method to attach my token to the authorization header in my Http client. Here's how I'm obtaining my token inside my service:
var accessToken = await tokenAcquisition.GetAccessTokenForUserAsync([$"{configuration["DownstreamApis:MyAPI:AppIdUri"]}/{configuration["DownstreamApis:MyAPI:Scope"]}"]);
The access token retrieved doesn't contain my custom claim userId. I tried passing my my ClaimsPrincipal object into GetAccessTokenForUserAsync like so, but had the same result:
var state = await _provider.GetAuthenticationStateAsync();
var principal = state.User;
var accessToken = await tokenAcquisition.GetAccessTokenForUserAsync([$"{configuration["DownstreamApis:MyAPI-API:AppIdUri"]}/{configuration["DownstreamApis:MyAPI:Scope"]}"], user: principal);
How do I persist my custom claims to pass into my API when using ITokenAquisition?
Here's my Blazor middleware setup:
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
builder.Services.AddOptions<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme).Configure(oidcOptions =>
{
oidcOptions.Scope.Add(OpenIdConnectScope.OfflineAccess);
});
Here's my API middleware:
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(o =>
{
var b2cConfig = builder.Configuration.GetSection("AzureAdB2C");
var tenantId = b2cConfig.GetValue<string>("TenantId");
var domains = b2cConfig.GetSection("ValidIssuerDomains").Get<List<string>>();
var validIssuers = domains?.Select(domain => $"https://{domain}/{tenantId}/v2.0/");
o.TokenValidationParameters.ValidIssuers = validIssuers;
o.TokenValidationParameters.RoleClaimType = "role";
o.TokenValidationParameters.NameClaimType = "sub";
o.IncludeErrorDetails = true;
}, options => builder.Configuration.Bind("AzureAdB2C", options));
UPDATED Roles are not mapping either. I looked at the HttpContext User object that ITokenAcquisition is supposed to be mapping to and my claims are in there, they just don't get mapped when calling GetAccessTokenForUserAsync().