title: AllowAnonymous is not ignored in ASP.NET Core custom AuthenticationHandler after migrating from .NET Core 2.2 to 3.1
body: <p>I have an ASP.NET Core 2.2 Web API which was working with the Basic Authentication. So far it worked fine and has no troubles. In one of the Controller, one Action Method is Decorated with <code>[AllowAnonymous]</code> to make the User Login, as usual.</p>
  
  <pre><code>[Produces("application/json")]
  [Route("user")]
  [AllowAnonymous]
  [ApiController]
  public class LoginController : ControllerBase
  {
      private readonly IConfiguration _configuration;
      private readonly IMessagingService _messageService;
      private readonly IBasicAuthenticationService _basicAuthenticationService;
      private readonly string PWAPIBaseUrl;
  
      public LoginController(IConfiguration configuration, ILogger&lt;LoginController&gt; logger, IMessagingService messagingService, IBasicAuthenticationService authenticationService)
      {
          _configuration = configuration;
          _logger = logger;
          _messageService = messagingService;
          _basicAuthenticationService = authenticationService;
      }
  
      [HttpGet]
      [AllowAnonymous]
      [Route("login/{username}/{clientID}")]
      public async Task&lt;IActionResult&gt; UserLogin(string username, string clientID)
      {
          // Check the Credentials Manually
          string failReason = "";
          if (!CheckCredentials(out failReason))
          {
              return StatusCode(StatusCodes.Status403Forbidden, userInfo);
          }
  
          // Load the Roles and UI Preferences ...
  
      }
  }
  </code></pre>
  
  <p>As the end of .NET Core 2.2 is near, I have tried upgrading to the .NET Core 3.1 and followed the <a href="https://docs.microsoft.com/en-us/aspnet/core/migration/22-to-30?view=aspnetcore-3.1&amp;tabs=visual-studio" rel="noreferrer">official Migration Guide</a> and made necessary <a href="https://docs.microsoft.com/en-us/dotnet/core/compatibility/2.2-3.1" rel="noreferrer">changes</a>. Though the Application started out smoothly, there is one bugging issue which forbids the upgrade.</p>
  
  <p>On the above controller, the [AllowAnonymous] is not ignored and the Authentication is evaluated and thrown out with an error. But the Login method is executed after. This causes Login to break in all the dependent applications. I have tried all the suggestions from Stackoverflow like <a href="https://stackoverflow.com/questions/58363002/custom-authenticationhandler-not-working-in-asp-net-core-3">this</a>, <a href="https://stackoverflow.com/questions/13595723/allowanonymous-not-working-with-custom-authorizationattribute">this</a> and <a href="https://stackoverflow.com/questions/47667949/asp-net-core-2-0-jwt-doesnt-ignore-allowanonymous">this</a>.</p>
  
  <p>Basic Authentication Handler:</p>
  
  <pre><code>public class BasicAuthenticationHandler : AuthenticationHandler&lt;AuthenticationSchemeOptions&gt;
  {
      private readonly ILogger&lt;BasicAuthenticationHandler&gt; _logger = null;
      private readonly IBasicAuthenticationService _basicAuthenticationService;
  
      public BasicAuthenticationHandler(
          IOptionsMonitor&lt;AuthenticationSchemeOptions&gt; options,
          UrlEncoder encoder,
          ILoggerFactory loggerFactory,
          ISystemClock clock,
          IBasicAuthenticationService authenticationService)
          : base(options, loggerFactory, encoder, clock)
      {
          _logger = loggerFactory.CreateLogger&lt;BasicAuthenticationHandler&gt;();
          _basicAuthenticationService = authenticationService;
      }
  
      protected override async Task&lt;AuthenticateResult&gt; HandleAuthenticateAsync()
      {
          var config = Util.GetConfig();
  
          if (!Request.Headers.ContainsKey("Authorization"))
          {
              _logger.LogError("No authorization credentials");
              return AuthenticateResult.NoResult();
          }
  
          if (!Request.Headers.ContainsKey("ClientID"))
          {
              _logger.LogError("Missing header client token");
              return AuthenticateResult.Fail("Missing header client token");
          }
  
          var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
          if (authHeader.Scheme != "Basic")
          {
              _logger.LogError("Authentication scheme not recognized");
              return AuthenticateResult.Fail("Authentication scheme not recognized");
          }
  
          var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
          var credentials = Encoding.UTF8.GetString(credentialBytes).Split(':');
          var username = credentials[0];
          var password = credentials[1];
  
          string fullname = "";
          string failReason = "";
          bool t = false;
  
          IPrincipal principal = null;
  
          // Do Business Validation against the DB
  
          if (!t) // login failed
          {
              byte[] bEncodedResponse = Encoding.UTF8.GetBytes(failReason);
              await Context.Response.Body.WriteAsync(bEncodedResponse, 0, bEncodedResponse.Length);
              return AuthenticateResult.Fail(failReason);
          }
          else
          {
              var claims = new[]
              {
                  new Claim(ClaimTypes.NameIdentifier, username),
                  new Claim(ClaimTypes.Name, fullname),
              };
  
              var identity = new ClaimsIdentity(claims, Scheme.Name);
              principal = principal==null?new ClaimsPrincipal(identity): principal;
              var ticket = new AuthenticationTicket(principal as ClaimsPrincipal, Scheme.Name);
  
              return AuthenticateResult.Success(ticket);
          }
      }
  
  
  }
  </code></pre>
  
  <p>Startup.cs</p>
  
  <pre><code>public class Startup
  {
      public Startup(IWebHostEnvironment environment, IConfiguration configuration, ILoggerFactory loggerFactory)
      {
          Environment = environment;
          Configuration = configuration;
          LoggerFactory = loggerFactory;
      }
  
      public IConfiguration Configuration { get; }
      public ILoggerFactory LoggerFactory { get; }
      public IWebHostEnvironment Environment { get; }
  
      public void ConfigureServices(IServiceCollection services)
      {
          services.AddAuthentication("BasicAuthentication")
              .AddScheme&lt;AuthenticationSchemeOptions, BasicAuthenticationHandler&gt;("BasicAuthentication", null);
  
          // Adding the Configuration Options -- Extension Methods to Inject Configuration as IOption POCOs
          services.ConfigureAPIOptions(Configuration);
  
          // configure DI for application services -- Other DI Objects
          services.ConfigureDependencies(Configuration, LoggerFactory);
  
          Common.APIConfiguration.Current = Configuration;
  
          services.AddControllers();
          services.AddAuthorization();
          if (Environment.IsDevelopment())
          {
              services.AddSwaggerGen(c =&gt;
              {
                  c.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo { Title = "My Materials API", Version = "v1" });
              });
          }
      }
  
      public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
      {
          app.UseRouting();
  
          if (env.IsDevelopment())
          {
              app.UseSwagger();
              app.UseSwaggerUI(c =&gt;
              {
                  c.SwaggerEndpoint("/swagger/v1/swagger.json", "My Materials API v1");
                  c.RoutePrefix = string.Empty;
              });
          }
  
          app.UseAuthentication();
          app.UseAuthorization();
          app.UseEndpoints(endpoints =&gt;
          {
              endpoints.MapControllers();
          });
      }
  }
  </code></pre>
  
  <p>I am still clueless on what I did wrong and I might be missing something in ASP.NET Core 3.1. Please help me in getting this working. Thanks in advance.</p>
  
  <p><strong>EDIT 1:</strong></p>
  
  <p>ServiceExtensions.cs</p>
  
  <pre><code>public static class ServiceExtensions
  {
      public static void ConfigureAPIOptions(this IServiceCollection services, IConfiguration configuration)
      {
          services.AddOptions();
          services.Configure&lt;DataSetting&gt;(configuration.GetSection("DataSettings"));
          services.Configure&lt;UrlSetting&gt;(configuration.GetSection("UrlSettings"));
          services.Configure&lt;SiteSettings&gt;(configuration.GetSection("SiteSettings"));
      }
  
      public static void ConfigureDependencies(this IServiceCollection services, IConfiguration configuration, ILoggerFactory loggerFactory)
      {
          services.AddSingleton&lt;IConfiguration&gt;(configuration);
          services.AddScoped&lt;IBasicAuthenticationService, BasicAuthenticationService&gt;();
          services.AddScoped&lt;IMessagingService&gt;(s =&gt; new MessagingServices(configuration, loggerFactory.CreateLogger&lt;MessagingServices&gt;()));
          services.AddHostedService&lt;TimedHostedService&gt;();
      }
  }
  </code></pre>
  
  <p>A Small Kludge for accessing the Configuration, where DI is not possible.</p>
  
  <pre><code>public static class APIConfiguration
  {
      public static IConfiguration Current { get; set; }
  }
  </code></pre>