[C#] Validate the X-API-KEY
After adding the X-API-KEY to the request, we need to validate it to ensure that the API key is correct and has the necessary permissions to access the requested resource. This can be done using middleware in our API. Here’s an example of how to validate the X-API-KEY using middleware in C#:
using Microsoft.AspNetCore.Http; public class ApiKeyMiddleware { private readonly RequestDelegate _next; public ApiKeyMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { if (!context.Request.Headers.TryGetValue("X-API-KEY", out var apiKey)) { context.Response.StatusCode = 401; await context.Response.WriteAsync("API key missing"); return; } if (apiKey != "YOUR_API_KEY") { context.Response.StatusCode = 401; await context.Response.WriteAsync("Invalid API key"); return; } await _next(context); } }
Configuring the middleware
To implement the above middleware for securing C# APIs with X-API-KEY, there are a few configurations that need to be made in our ASP.NET Core application:
public class ApiKeyValidator : IApiKeyValidator { private readonly IConfiguration _configuration; public ApiKeyValidator(IConfiguration configuration) { _configuration = configuration; } public bool Validate(string apiKey) { // Retrieve the expected API key from the app settings var expectedApiKey = _configuration.GetValue<string>("ApiKeys:MyApiKey"); // Compare the provided API key with the expected API key return apiKey == expectedApiKey; } }
public interface IApiKeyValidator { bool Validate(string apiKey); }
In .Net Core:
public class Startup { public void ConfigureServices(IServiceCollection services) { // Add the ApiKeyValidator as a singleton services.AddSingleton<IApiKeyValidator, ApiKeyValidator>(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // Add the ApiKeyMiddleware to the middleware pipeline app.UseMiddleware<ApiKeyMiddleware>(); // Add any additional middleware here, such as authentication middleware } }
In .Net 5, 6:
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; var builder = WebApplication.CreateBuilder(args); builder.Services.AddSingleton<IApiKeyValidator, MyApiKeyValidator>(); // Add the API key middleware to the pipeline builder.Use(async (context, next) => { // Get the API key from the X-API-KEY header var apiKey = context.Request.Headers["X-API-KEY"]; // Validate the API key using the IApiKeyValidator service var apiKeyValidator = context.RequestServices.GetRequiredService<IApiKeyValidator>(); if (!apiKeyValidator.Validate(apiKey)) { // If the API key is invalid, return a 401 Unauthorized response context.Response.StatusCode = StatusCodes.Status401Unauthorized; return; } // If the API key is valid, pass the request to the next middleware in the pipeline await next.Invoke(); }); builder.MapGet("/hello", (HttpContext context) => { // If the API key is valid, return a 200 OK response with a "Hello, world!" message context.Response.StatusCode = StatusCodes.Status200OK; return context.Response.WriteAsync("Hello, world!"); }); var app = builder.Build(); app.Run();
Creating the Attribute
We can create an ApiKeyAttribute that we can use to decorate our controllers and actions in C#:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; public class ApiKeyAttribute : ActionFilterAttribute { private readonly IApiKeyValidator _apiKeyValidator; public ApiKeyAttribute(IApiKeyValidator apiKeyValidator) { _apiKeyValidator = apiKeyValidator; } public override void OnActionExecuting(ActionExecutingContext context) { // Get the API key from the X-API-KEY header var apiKey = context.HttpContext.Request.Headers["X-API-KEY"]; // Validate the API key using the IApiKeyValidator service if (!_apiKeyValidator.Validate(apiKey)) { // If the API key is invalid, set the response status code to 401 Unauthorized context.Result = new UnauthorizedResult(); return; } // If the API key is valid, continue with the action execution base.OnActionExecuting(context); } }
[ApiController] [Route("api/[controller]")] [ApiKey] // decorate the controller with the ApiKeyAttribute public class MyController : ControllerBase { [HttpGet] [ApiKey] // decorate the action with the ApiKeyAttribute public IActionResult Get() { return Ok("Hello, world!"); } }