Ktos.AspNetCore.Authentication.ApiKeyHeader
Authentication using X-APIKEY HTTP header for ASP.NET Core
Install / Use
/learn @ktos/Ktos.AspNetCore.Authentication.ApiKeyHeaderREADME
Ktos.AspNetCore.Authentication.ApiKeyHeader
Authentication for ASP.NET Core Security using HTTP header like X-APIKEY and
simple single provided key.
This authentication method, while very simple, is of course not suitable for production systems due to potential insecurities. However, as fast and simple method, still could be useful in situations you don't wan't to use token-based security.
Sample usage
Configure your authentication method in Program.cs:
// ...
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = ApiKeyHeaderAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = ApiKeyHeaderAuthenticationDefaults.AuthenticationScheme;
})
.AddApiKeyHeaderAuthentication(options => options.ApiKey = "my-secret-api-key");
Remember about activating it later:
app.UseAuthentication();
app.UseAuthorization();
It requires you to authenticate to sent X-APIKEY header along with your
request, with a value equal to the secret key you set in options, or the request
will fail with 401 Unauthorized HTTP error.
Of course, you have to ensure your controller or actions are expecting user to
be authenticated, for example you can use [Authorize].
See Microsoft docs for more.
Simplified version for .NET 7.0
In ASP.NET Core 7.0, when using only one AuthenticationScheme, you can use
simpler version:
builder.Services.AddAuthentication()
.AddApiKeyHeaderAuthentication(options => options.ApiKey = "my-secret-api-key");
Custom header
You can use any header, by configuring options, e.g. you can set you want
x-api-key, not X-APIKEY:
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = ApiKeyHeaderAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = ApiKeyHeaderAuthenticationDefaults.AuthenticationScheme;
})
.AddApiKeyHeaderAuthentication(options => { options.ApiKey = "my-secret-api-key"; options.Header = "x-api-key"; });
// ...
Custom logic (simple)
You may use option CustomAuthenticationHandler to provide a function which will be used to perform a validation of your key. For example let's use a simple method:
private (bool, string) SimpleCustomAuthenticationLogic(string apiKey)
{
if (apiKey == "abc123") return (true, "Jon");
if (apiKey == "def234") return (true, "Snow");
return (false, string.Empty);
}
Your function must be matching CustomApiKeyHandlerDelegate delegate -- input
parameters is a string, the user-provided API key, the result should be a tuple
of bool and string -- where the bool value is telling if the authentication is
successful, and the string value is the user name to be used in
AuthenticationTicket.Principal.Identity.Name, so you may differentiate about
it later.
Custom logic (more advanced)
In Startup.cs you may provide a type as a singleton, implementing an
IApiKeyCustomAuthenticator interface, which will be acquired from current
request services to be used for authentication. You have to set option for
UseRegisteredAuthenticationHandler to true.
In that case, you may use it for database connection, checking users API key usage limits or similar things before authentication.
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = ApiKeyHeaderAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = ApiKeyHeaderAuthenticationDefaults.AuthenticationScheme;
})
.AddApiKeyHeaderAuthentication(options => options.UseRegisteredAuthenticationHandler = true);
builder.Services.AddSingleton<TestApiKeyService>();
The interface requires for you implementation of a method returning a pair of
bool and string, where bool indicates if the authentication was successful, and
in the string you may provide a name, which will be used in created
AuthenticationTicket.Claims as Principal.Identity.Name so you may
differentiate between different users.
In this example, a simple ILogger<T> is used:
internal class TestApiKeyService : IApiKeyCustomAuthenticator
{
private readonly ILogger logger;
public TestApiKeyService(ILogger<TestApiKeyService> logger)
{
this.logger = logger;
this.logger.LogInformation("Created a test authenticator");
}
// returns true on "testapi", returns uppercase key as name, false in any other case
public CustomApiKeyHandlerDelegate CustomAuthenticationHandler => (key) =>
{
logger.LogDebug($"Someone tried to authenticate with API key: {key}");
return key == "testapi" ? (true, key.ToUpper()) : (false, null);
};
}
Custom logic (full AuthorizationTicket)
If UseRegisteredAuthenticationHandler is set to true and there is a registered
singleton implementing an IApiKeyCustomAuthenticatorFullTicket interface, it
will be used automatically.
This interface allows to create a custom method returning full
AuthorizationTicket as you need - e.g. with proper claims or roles you are
using later.
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = ApiKeyHeaderAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = ApiKeyHeaderAuthenticationDefaults.AuthenticationScheme;
})
.AddApiKeyHeaderAuthentication(options => options.UseRegisteredAuthenticationHandler = true);
builder.Services.AddSingleton<CustomFullTicketHandler>();
The class implementing IApiKeyCustomAuthenticatorFullTicket is being created
with dependency injection, so it may access database or other services useful
for your own authentication logic.
The interface requires for you implementation of a method returning an
AuthorizationTicket, which you can customize, for example:
internal class CustomFullTicketHandler : IApiKeyCustomAuthenticatorFullTicket
{
public AuthenticateResult CustomAuthenticationHandler(string key)
{
if (key == "goodkey")
return AuthenticateResult.Success(CreateAuthenticationTicket());
return AuthenticateResult.NoResult();
}
private AuthenticationTicket CreateAuthenticationTicket()
{
var claims = new[] {
new Claim(ClaimTypes.Name, "Jon Snow"),
new Claim(ClaimTypes.Role, "testrole")
};
var identity = new ClaimsIdentity(claims, ApiKeyHeaderAuthenticationDefaults.AuthenticationScheme);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, ApiKeyHeaderAuthenticationDefaults.AuthenticationScheme);
ticket.Properties.RedirectUri = "http://localhost";
return ticket;
}
}
Mixing Options
Mixing options of Options.ApiKey, Options.CustomAuthenticationHandler and
Options.UseRegisteredAuthenticationHandler may result in unexpected results,
please treat them as mutually exclusive.
- If the header is empty, no logic is being applied;
- If not and
CustomAuthenticationHandleris not null andUseRegisteredAuthenticationHandleris false,CustomAuthenticationHandler(method) is used; - If not and
CustomAuthenticationHandleris true and handler of typeIApiKeyCustomAuthenticatoris registered, it will be used; - If not and
CustomAuthenticationHandleris true and handler returning tickets (IApiKeyCustomAuthenticationTicketHandler) is registered, it will be used; - If not, but the header field value is equal to
Options.ApiKeyandUseRegisteredAuthenticationHandleris false, Options.ApiKey will be used.
In any other case, NoResult() is returned.
License
Licensed under MIT
Have a lot of fun. --ktos
Related Skills
gh-issues
336.5kFetch GitHub issues, spawn sub-agents to implement fixes and open PRs, then monitor and address PR review comments. Usage: /gh-issues [owner/repo] [--label bug] [--limit 5] [--milestone v1.0] [--assignee @me] [--fork user/repo] [--watch] [--interval 5] [--reviews-only] [--cron] [--dry-run] [--model glm-5] [--notify-channel -1002381931352]
healthcheck
336.5kHost security hardening and risk-tolerance configuration for OpenClaw deployments
node-connect
336.5kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
oracle
336.5kBest practices for using the oracle CLI (prompt + file bundling, engines, sessions, and file attachment patterns).
