[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!");
    }
}