No authenticationScheme was specified, and there was no DefaultForbidScheme found with custom policy based authorization

Authorization and authentication are closely linked in ASP.NET Core. When authorization fails, this will be passed to an authentication handler to handle the authorization failure.

So even if you don’t need actual authentication to identify your users, you will still need to set up some authentication scheme that is able to handle forbid and challenge results (403 and 401).

To do that, you need to call AddAuthentication() and configure a default forbid/challenge scheme:

services.AddAuthentication(options =>
{
    options.DefaultChallengeScheme = "scheme name";

    // you can also skip this to make the challenge scheme handle the forbid as well
    options.DefaultForbidScheme = "scheme name";

    // of course you also need to register that scheme, e.g. using
    options.AddScheme<MySchemeHandler>("scheme name", "scheme display name");
});

MySchemeHandler needs to implement IAuthenticationHandler and in your case, you especially need to implement ChallengeAsync and ForbidAsync:

public class MySchemeHandler : IAuthenticationHandler
{
    private HttpContext _context;

    public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
    {
        _context = context;
        return Task.CompletedTask;
    }

    public Task<AuthenticateResult> AuthenticateAsync()
        => Task.FromResult(AuthenticateResult.NoResult());

    public Task ChallengeAsync(AuthenticationProperties properties)
    {
        // do something
    }

    public Task ForbidAsync(AuthenticationProperties properties)
    {
        // do something
    }
}

For IIS/IIS Express, can just add this line instead of all of the above in the accepted answer to get the appropriate 403 response you're expecting;

 services.AddAuthentication(IISDefaults.AuthenticationScheme);