Cannot Authorize Scopes in Web API M2M

In my scenario, I have a back-end repository from a web application calling a Web API resource using the Machine-to-machine (Client Credentials) flow. The authentication part works fine – the respository is able to get an access token from Auth0 and the API accepts the request. Now I am trying to authorize the Web API endpoint with a scope, which fails.

I followed the instructions in the Auth0 documentation to register an application for the web application, create an API, and create a scope in the API which the application is authorized to use.

In the repository, I make the request with the token:

HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, $"v2/staff/{username}");
var m2mToken = (await _auth0.GetM2MToken()).ToDto(); // Auth0 machine-to-machine access token
request.Headers.Add("Access-Token", m2mToken.AccessToken);
var message = await _httpClient.SendAsync(request);

On the API end, I added a policy rule to enforce the scope authorization:

var auth0Section = Configuration.GetSection("Auth0").Get<Dictionary<string, string>>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
    options.Authority = auth0Section["Domain"];
    options.Audience = auth0Section["Audience"];
    options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
    {
        NameClaimType = ClaimTypes.NameIdentifier
    };
});

services.AddAuthorization(options =>
{
    options.AddPolicy("access_as_user", policy => policy.Requirements.Add(new HasScopeRequirement("access_as_user", auth0Section["Domain"])));
});
services.AddSingleton<IAuthorizationHandler, HasScopeHandler>();

Then I created the scope requirement and handler classes.

public class HasScopeHandler : AuthorizationHandler<HasScopeRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasScopeRequirement requirement)
    {
        // If user does not have the scope claim, get out of here
        if (!context.User.HasClaim(c => c.Type == "scope" && c.Issuer == requirement.Issuer))
            return Task.CompletedTask;

        // Split the scopes string into an array
        var scopes = context.User.FindFirst(c => c.Type == "scope" && c.Issuer == requirement.Issuer)?.Value.Split(' ') ?? System.Array.Empty<string>();

        // Succeed if the scope array contains the required scope
        if (scopes.Any(s => s == requirement.Scope))
            context.Succeed(requirement);

        return Task.CompletedTask;
    }
}

Finally, I set the endpoint to require the scope in question.

[Authorize(Policy = "access_as_user")]
[HttpGet("{username}")]
public async Task<Microsoft.AspNetCore.Mvc.ActionResult> GetStaffRecordByUsername(string username)
{
    ...
}

But in the HasScopeHandler, the context.User claims do not include any “Scope” type claims, so the requirement fails. Am I missing some configuration in Auth0 or my Web API to get the claims I need?

I should note that I’m running both ends in debug mode on my development machine, if it changes anything.

One futher note: when I get the access token, it does include the “scope” member, which lists the scope in question.