Trying to add Azure/Microsoft AD to my application. I already have JWT token in place, which means 2 JWT tokens should be validated. It's in an Angular + .NET 6 App.
Here is the documentation explaining the Microsoft AD part: Docs1, specific for SPA app: github docs
As per documentation and this stackoverflow answer, I have tried doing so:
Program.cs:
var builder = WebApplication.CreateBuilder(args);
var configuration = builder.Configuration;
// Add services to the container.
builder.Services.AddDbContext<DatabaseContext>(options =>
            options.UseSqlServer(configuration.GetConnectionString("DatabaseContext")));
if (builder.Environment.IsDevelopment())
{
    builder.Services.AddDatabaseDeveloperPageExceptionFilter();
}
builder.Services.AddIdentity<ApplicationUser, ApplicationRole>()
    .AddEntityFrameworkStores<DatabaseContext>()
    .AddDefaultTokenProviders();
builder.Services.AddSession();
IdentityModelEventSource.ShowPII = true;   // For debugging purposes
builder.Services.AddAuthentication()
.AddJwtBearer("InternalBearer", options =>
{
    options.Audience = configuration["settings:PortalUrl"];
    options.Authority = configuration["settings:PortalUrl"];
    options.SaveToken = true;
    options.RequireHttpsMetadata = false;
    options.Configuration = new OpenIdConnectConfiguration();
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = configuration["settings:PortalUrl"],
        ValidAudience = configuration["settings:PortalUrl"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["settings:SecurityKey"]))
    };
})
.AddMicrosoftIdentityWebApi(configuration, "AzureAd", subscribeToJwtBearerMiddlewareDiagnosticsEvents: true);
// Creating policies that wraps the authorization requirements
builder.Services
    .AddAuthorization(options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder()
            .AddAuthenticationSchemes("InternalBearer", JwtBearerDefaults.AuthenticationScheme)
            .RequireAuthenticatedUser()
            .Build();
    });
builder.Services.AddMvc().AddNewtonsoftJson(o =>
{
    o.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    o.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore;
    o.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    //o.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
})
    .ConfigureApplicationPartManager(apm =>
        apm.FeatureProviders.Add(new ModuleControllerFeatureProvider(configuration)));
....
var app = builder.Build();
app.UseRouting();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
                   name: "default",
                   pattern: "{controller}/{action=Index}/{id?}");
});
Here is my account controller, remember that the JWT token creation and validation was working before when just using 1 authentication scheme. Before I've set the DefaultAuthenticationScheme within AddAuthentication() method.
AccountController:
[HttpGet("[action]")]
public IActionResult Get()
{
    _logger.LogInformation("Get - Retrieving contact details");
    var userId = HttpContext.User.FindFirst(ClaimTypes.Name)?.Value;
    if (userId == null)
    {
        return NotFound();
    }
    return Ok(userId);    // for testing purposes now
}
[AllowAnonymous]
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginDTO login)
{
    var user = await _userManager.FindByEmailAsync(login.Email);
    if (user == null)
    {
        return BadRequest();
    }
    var succeeded = await _userManager.CheckPasswordAsync(user, login.Password);
    if (succeeded)
    {
        // add claims to token
        var roles = await _userManager.GetRolesAsync(user);
        List<Claim> claims = new List<Claim> { new Claim(ClaimTypes.Name, user.Id), new Claim(ClaimTypes.Email, user.Email) };
        foreach (string role in roles)
        {
            claims.Add(new Claim(ClaimTypes.Role, role));
        }
        ClaimsIdentity identity = new ClaimsIdentity(claims);
        var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["settings:SecurityKey"]));
        var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256Signature);
        var tokenOptions = new SecurityTokenDescriptor()
            {
                Issuer = _config["settings:PortalUrl"],
                Audience = _config["settings:PortalUrl"],
                Expires = DateTime.UtcNow.AddDays(7).Date,
                SigningCredentials = signinCredentials,
                Subject = identity
            };
        var tokenHandler = new JwtSecurityTokenHandler();
        var token = tokenHandler.CreateToken(tokenOptions);
        string tokenStr = tokenHandler.WriteToken(token);
        return Ok(new { Token = tokenStr });
    }
    return BadRequest();
}
I've re-configured the front-end to now use InternalBearer  as prefix for every authenticated request. Of course I have validated this, in Swagger:
curl -X 'GET' \
  'https://localhost:44322/api/Account/Get' \
  -H 'accept: */*' \
  -H 'Authorization: InternalBearer eyJhb...8Eh0'
When I try to access the Account/get endpoint, I get a 401 and I see this logging:
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request starting HTTP/2 GET https://localhost:44322/api/account/get - -
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed. These requirements were not met:
DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler: Information: AuthenticationScheme: InternalBearer was challenged.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler: Information: AuthenticationScheme: Bearer was challenged.
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request finished HTTP/2 GET https://localhost:44322/api/account/get - - - 401 - - 12.1477ms
When I do use Bearer  as pre-fix in the Authorization header, it seems I can access the Account/Get endpoint! I thought that was it, not perfect but hey, 'it was working'.
Boy was I wrong, because when I try to access another endpoint that has a Role added to it, I was getting the following output:
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService: Information: Authorization failed. These requirements were not met:
RolesAuthorizationRequirement:User.IsInRole must be true for one of the following roles: (Portal)
That controller simply has [Authorize(Roles = "Portal")] added to it, I'm 100% the logged in user has this role, because in my IClaimsTransformation I can see the role is being present. Yet again: It was working before with just one AuthenticationScheme.
The logging does give me some other issues, yet I think this has to do with the fact that I try to use the Bearer  prefix, so the wrong AuthenticationScheme is used and thus the wrong validation is used. But if interested:
Microsoft.IdentityModel.LoggingExtensions.IdentityLoggerAdapter: Error: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: '[PII of type 'Microsoft.IdentityModel.Tokens.RsaSecurityKey' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
Microsoft.IdentityModel.LoggingExtensions.IdentityLoggerAdapter: Information: IDX10243: Reading issuer signing keys from validation parameters.
Microsoft.IdentityModel.LoggingExtensions.IdentityLoggerAdapter: Information: IDX10265: Reading issuer signing keys from configuration.
Microsoft.IdentityModel.LoggingExtensions.IdentityLoggerAdapter: Error: IDX10503: Signature validation failed. Token does not have a kid. Keys tried: '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. Number of keys in TokenValidationParameters: '14'. 
Number of keys in Configuration: '0'. 
Exceptions caught:
 '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
token: '[PII of type 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler: Information: Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenSignatureKeyNotFoundException: IDX10503: Signature validation failed. Token does not have a kid. Keys tried: '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. Number of keys in TokenValidationParameters: '14'. 
Number of keys in Configuration: '0'. 
Exceptions caught:
 '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
token: '[PII of type 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignatureAndIssuerSecurityKey(String token, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters, BaseConfiguration configuration)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateJWS(String token, TokenValidationParameters validationParameters, BaseConfiguration currentConfiguration, SecurityToken& signatureValidatedToken, ExceptionDispatchInfo& exceptionThrown)
--- End of stack trace from previous location ---
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, JwtSecurityToken outerToken, TokenValidationParameters validationParameters, SecurityToken& signatureValidatedToken)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
   at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler: Information: Bearer was not authenticated. Failure message: IDX10503: Signature validation failed. Token does not have a kid. Keys tried: '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. Number of keys in TokenValidationParameters: '14'. 
Number of keys in Configuration: '0'. 
Exceptions caught:
 '[PII of type 'System.Text.StringBuilder' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
token: '[PII of type 'System.IdentityModel.Tokens.Jwt.JwtSecurityToken' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.
Microsoft.AspNetCore.Routing.EndpointMiddleware: Information: Executing endpoint 'CularBytes.Core.Controllers.V1.LinkController.GetLinkAllowed (CularBytes.Core.Controllers)'
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Information: Route matched with {action = "GetLinkAllowed", controller = "Link", page = ""}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult GetLinkAllowed(LinkModel) on controller CularBytes.Core.Controllers.V1.LinkController (CularBytes.Core.Controllers).
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Information: Executing action method CularBytes.Core.Controllers.V1.LinkController.GetLinkAllowed (CularBytes.Core.Controllers) - Validation state: Valid
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Information: Executed action method CularBytes.Core.Controllers.V1.LinkController.GetLinkAllowed (CularBytes.Core.Controllers), returned result Microsoft.AspNetCore.Mvc.OkObjectResult in 0.0635ms.
Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor: Information: Executing OkObjectResult, writing value of type 'CularBytes.Core.Controllers.V1.LinkController+LinkResult'.
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker: Information: Executed action CularBytes.Core.Controllers.V1.LinkController.GetLinkAllowed (CularBytes.Core.Controllers) in 11.8873ms
Microsoft.AspNetCore.Routing.EndpointMiddleware: Information: Executed endpoint 'CularBytes.Core.Controllers.V1.LinkController.GetLinkAllowed (CularBytes.Core.Controllers)'
Microsoft.AspNetCore.Hosting.Diagnostics: Information: Request finished HTTP/2 POST https://localhost:44322/api/link/allowed application/json 97 - 200 16 application/json;+charset=utf-8 185.5499ms
When I log in via the Microsoft flow, I also get an error saying:
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler: Information: Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenUnableToValidateException: IDX10516: Signature validation failed. Unable to match key: 
kid: '2ZQ.....TOI'. 
Number of keys in TokenValidationParameters: '0'. 
Number of keys in Configuration: '1'. 
Which is also strange, perhaps it has something to do with each other.
I guess I am doing something wrong in the configuration, hope you can tell me what that is!
UPDATE
I started a GitHub issue here, where I used a simple template project so that should help with taking away all the project-related issues: https://github.com/dotnet/aspnetcore/issues/43467
