Provides tools to configure Basic authentication for ASP.NET Core with extensible validation strategies.
This library simplifies the setup of HTTP Basic Authentication in ASP.NET Core applications with a flexible, extensible architecture. It supports:
- Simple scenarios: Static credentials embedded in options
- Configuration-based: Credentials from
appsettings.json - Advanced scenarios: Custom validators with database, LDAP, or external service integration
- Generic options: Extend
BasicAuthenticationOptionsfor custom properties - Multiple schemes: Support for multiple authentication schemes
dotnet add package qckdev.AspNetCore.Authentication.Basic
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection;
using qckdev.AspNetCore.Authentication.Basic;
services
.AddAuthentication("Basic")
.AddBasicAuthentication<CredentialsBasedValidator, CredentialsBasedOptions>(opts =>
{
opts.Realm = "My API";
opts.Username = "admin";
opts.Password = "secretPassword123";
});
Then use the [Authorize(AuthenticationSchemes = "Basic")] attribute on your controllers:
[ApiController]
[Route("api/[controller]")]
[Authorize(AuthenticationSchemes = "Basic")]
public class ProtectedController : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
var username = User.Identity?.Name;
return Ok(new { message = $"Hello, {username}!" });
}
}
Implement a custom validator to check credentials against a database:
using qckdev.AspNetCore.Authentication.Basic;
using System.Threading;
using System.Threading.Tasks;
public class DatabaseValidator : IBasicAuthenticationValidator
{
private readonly IUserService _userService;
private readonly IPasswordHasher _passwordHasher;
public DatabaseValidator(IUserService userService, IPasswordHasher passwordHasher)
{
_userService = userService;
_passwordHasher = passwordHasher;
}
public async Task<bool> ValidateAsync(string username, string password, CancellationToken cancellationToken = default)
{
try
{
var user = await _userService.GetUserAsync(username, cancellationToken);
if (user == null) return false;
return _passwordHasher.Verify(user.PasswordHash, password);
}
catch
{
return false;
}
}
}
Register it in your Startup.cs or Program.cs:
services
.AddScoped<IUserService, UserService>()
.AddScoped<IPasswordHasher, PasswordHasher>()
.AddAuthentication("Basic")
.AddBasicAuthentication<DatabaseValidator>(opts =>
{
opts.Realm = "Enterprise API";
});
You can register multiple Basic authentication schemes with different validators:
services
.AddAuthentication("Basic")
.AddBasicAuthentication<CredentialsBasedValidator, CredentialsBasedOptions>(
"ApiKey",
opts =>
{
opts.Realm = "Legacy API";
opts.Username = "api-key";
opts.Password = "legacy-shared-secret";
})
.AddBasicAuthentication<DatabaseValidator>(
"Database",
opts =>
{
opts.Realm = "Enterprise API";
});
Then use specific schemes on your controllers:
[Authorize(AuthenticationSchemes = "ApiKey")]
public class LegacyController : ControllerBase { }
[Authorize(AuthenticationSchemes = "Database")]
public class EnterpriseController : ControllerBase { }
Extend BasicAuthenticationOptions to add custom properties:
public class CustomBasicOptions : BasicAuthenticationOptions
{
public string? ApiVersion { get; set; }
public int MaxLoginAttempts { get; set; } = 5;
}
Use it with your validator:
services
.AddAuthentication()
.AddBasicAuthentication<DatabaseValidator, CustomBasicOptions>(opts =>
{
opts.Realm = "My API";
opts.ApiVersion = "v1";
opts.MaxLoginAttempts = 3;
});
| Property | Type | Default | Description |
|---|---|---|---|
Realm |
string? |
"Application" |
The realm sent in the WWW-Authenticate header (RFC 7617) |
AllowEmptyCredentials |
bool |
false |
Whether to allow empty username or password |
Encoding |
Encoding? |
UTF-8 |
Character encoding for decoding credentials |
| Property | Type | Description |
|---|---|---|
Username |
string? |
The username for static authentication |
Password |
string? |
The password for static authentication |
Uses static credentials from CredentialsBasedOptions. Performs case-sensitive string comparison.
.AddBasicAuthentication<CredentialsBasedValidator, CredentialsBasedOptions>(opts =>
{
opts.Username = "admin";
opts.Password = "password123";
});
Create a custom validator by implementing IBasicAuthenticationValidator:
public interface IBasicAuthenticationValidator
{
Task<bool> ValidateAsync(string username, string password, CancellationToken cancellationToken = default);
}
Example with external service:
public class ExternalServiceValidator : IBasicAuthenticationValidator
{
private readonly HttpClient _httpClient;
public ExternalServiceValidator(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<bool> ValidateAsync(string username, string password, CancellationToken cancellationToken = default)
{
var request = new { username, password };
var response = await _httpClient.PostAsJsonAsync(
"https://auth-service.example.com/validate",
request,
cancellationToken);
return response.IsSuccessStatusCode;
}
}
Use Basic Authentication as a simple API key mechanism:
// Startup
services
.AddAuthentication()
.AddBasicAuthentication<CredentialsBasedValidator, CredentialsBasedOptions>(
"ApiKey",
opts =>
{
opts.Realm = "API Key Authentication";
opts.Username = "ApiKey"; // Fixed username
opts.Password = "your-secret-api-key-token";
});
// Usage: Pass as Authorization header
// Authorization: Basic QXBpS2V5OnlvdXItc2VjcmV0LWFwaS1rZXktdG9rZW4=
✅ Extensible validation strategy pattern
✅ Multiple authentication schemes
✅ Generic options class inheritance
✅ Thread-safe credential validation
✅ XML documentation
✅ No external dependencies (uses only ASP.NET Core built-ins)
- Production: Always use HTTPS when transmitting Basic Authentication credentials
- Password storage: Hash and salt passwords, never store plain text
- Validation: Implement timeout and rate-limiting in custom validators
- Realm: Use descriptive realm names to help clients understand the protected resource
- Claims: Consider adding claims mapping in custom validators for authorization
This library includes comprehensive integration tests covering credential validation, header parsing, and edge cases.
7 integration tests validate the complete authentication pipeline:
- Public endpoint access
- Challenge response (WWW-Authenticate)
- Valid and invalid credentials
- Malformed headers
- Edge cases (empty password, etc.)
For detailed testing documentation, see Integration Testing Guide.
- .NET Core 3.1
- .NET 5.0
- .NET 6.0
- .NET 8.0
- .NET 10.0
MIT License - See LICENSE file for details
Contributions are welcome! Please submit issues and pull requests on GitHub.