Dipping my toes for the very first time into the world of Web API and MVC.
Here's my program.cs:
namespace TelephoneInfoLookup;
using TelephoneInfoLookup.Middleware;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.DefaultIgnoreCondition =
            System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull;
    });
builder.Services.AddEndpointsApiExplorer()
    .AddSwaggerGen()
    .AddCors()
    .AddAuthentication("Basic");
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
    app.UseSwagger()
        .UseDeveloperExceptionPage()
        .UseSwaggerUI();
}
else
    app.UseHsts();
app.UseHttpsRedirection()
    .UseMiddleware<BasicAuthMiddleware>(new BasicAuthenticationOptions
    {
        Name = "Bob",
        Password = "My Uncle"
    })
    .UseAuthorization();
app.MapControllers();
app.Run();
And this is the middleware:
namespace TelephoneInfoLookup.Middleware;
using System.Net;
using System.Security.Principal;
public class BasicAuthMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly BasicAuthenticationOptions _options;
        public BasicAuthMiddleware(RequestDelegate next, BasicAuthenticationOptions options)
        {
            _next = next;
            _options = options ?? throw new ArgumentException("User info can't be null");
        }
        public async Task Invoke(HttpContext context)
        {
            if (CheckIsValidRequest(context, out string username))
            {
                var identity = new GenericIdentity(username);
                var principle = new GenericPrincipal(identity, null);
                context.User = principle;
                await _next.Invoke(context);
            }
            else
            {
                context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
            }
        }
        private bool CheckIsValidRequest(HttpContext context, out string username)
        {
            var basicAuthHeader = GetBasicAuthenticationHeaderValue(context);
            username = basicAuthHeader.UserName;
            return basicAuthHeader.IsValidBasicAuthenticationHeaderValue &&
                   basicAuthHeader.UserName == _options.Name &&
                   basicAuthHeader.Password == _options.Password;
        }
        private BasicAuthenticationHeaderValue GetBasicAuthenticationHeaderValue(HttpContext context)
        {
            var basicAuthenticationHeader = context.Request.Headers["Authorization"]
                .FirstOrDefault(header => header.StartsWith("Basic", StringComparison.OrdinalIgnoreCase));
            var decodedHeader = new BasicAuthenticationHeaderValue(basicAuthenticationHeader);
            return decodedHeader;
        }
    }
    public class BasicAuthenticationOptions
    {
        public string Name { get; set; }
        public string Password { get; set; }
    }
    public class BasicAuthenticationHeaderValue
    {
        public BasicAuthenticationHeaderValue(string authenticationHeaderValue)
        {
            if (!string.IsNullOrWhiteSpace(authenticationHeaderValue))
            {
                _authenticationHeaderValue = authenticationHeaderValue;
                if (TryDecodeHeaderValue())
                {
                    ReadAuthenticationHeaderValue();
                }
            }
        }
        private readonly string _authenticationHeaderValue;
        private string[] _splitDecodedCredentials;
        public bool IsValidBasicAuthenticationHeaderValue { get; private set; }
        public string UserName { get; private set; }
        public string Password { get; private set; }
        private bool TryDecodeHeaderValue()
        {
            const int headerSchemeLength = 6;
            if (_authenticationHeaderValue.Length <= headerSchemeLength)
            {
                return false;
            }
            var encodedCredentials = _authenticationHeaderValue.Substring(headerSchemeLength);
            try
            {
                var decodedCredentials = Convert.FromBase64String(encodedCredentials);
                _splitDecodedCredentials = System.Text.Encoding.ASCII.GetString(decodedCredentials).Split(':');
                return true;
            }
            catch (FormatException)
            {
                return false;
            }
        }
        private void ReadAuthenticationHeaderValue()
        {
            IsValidBasicAuthenticationHeaderValue = _splitDecodedCredentials.Length == 2
                                                   && !string.IsNullOrWhiteSpace(_splitDecodedCredentials[0])
                                                   && !string.IsNullOrWhiteSpace(_splitDecodedCredentials[1]);
            if (IsValidBasicAuthenticationHeaderValue)
            {
                UserName = _splitDecodedCredentials[0];
                Password = _splitDecodedCredentials[1];
            }
        }
    }
With this I'm able to ensure that only user Bob with the password of My Uncle can use this endpoint:
namespace TelephoneInfoLookup.Controllers;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("[Controller]")]
[Produces("application/json")]
[Authorize]
public class LookupController : ControllerBase
{
    private readonly ILogger<LookupController> _logger;
    public LookupController(ILogger<LookupController> logger)
    {
        _logger = logger;
    }
    [HttpGet]
    public async Task<Lookup> Get(string telephoneNumber, string fields)
    {
        var ret = await Lookup.LookupDetails(telephoneNumber, fields);
        return ret;
    }
}
However another method that I want to be left open still demands I use basic authentication and I get a 401 whenever I try to call it:
namespace TelephoneInfoLookup.Controllers;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[AllowAnonymous]
[ApiController]
[Route("Simple")]
public class SimpleLookupController : ControllerBase
{
    private readonly ILogger<LookupController> _logger;
    public SimpleLookupController(ILogger<LookupController> logger)
    {
        _logger = logger;
    }
    [HttpGet]
    [AllowAnonymous]
    public async Task<string> GetExtension(string telephoneNumber)
    {
        var lookup = await Lookup.LookupDetails(telephoneNumber, null);
        var ret = lookup!.VIPExtension!;
        return string.IsNullOrEmpty(ret) ? "" : ret;
    }
}
I tried things like adding
app.UseHttpsRedirection()
    .UseMiddleware<BasicAuthMiddleware>(new BasicAuthenticationOptions
    {
        Name = "Bob",
        Password = "Your Uncle"
    })
    .UseAuthentication()
    .UseAuthorization();
but to no avail.
What silly thing am I missing in this?
I suspect it's something in the Middleware that needs to be changed, but since I'm totally green at all this, I'm rather perplexed.
I did spend some time trying to get my head around AllowAnonymous not working with Custom AuthorizationAttribute which would lead me to think I may be in need of utilizing something using System.Web.Http.AuthorizeAttribute but I'm kinda lost how I'd use that in my code (well, not my code, someone else's that I found that got my basic authentication "working"!)