4

I have a Web API project that has a number of endpoints that are protected using an API key. To achieve this I have written some middleware to handle checking the header for the API key and validating it. This middleware is configured in the Startup.cs

app.UseMiddleware<ApiKeyMiddleware>();

This works perfectly, however I now have the requirement to have one endpoint that does not require any authorisation so it can be viewed in browser. I was hoping this would be done by using the AllowAnonymous attribute, however the middleware still checks for the API key.

I can achieve what I want by removing the middleware and making the API key check into an attribute, but is there a better way to do this?

EDIT:

This is the API key middleware implementation.

public class ApiKeyMiddleware
{
    private readonly RequestDelegate _next;
    private const string API_KEY_HEADER = "z-api-key";
    
    public ApiKeyMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    
    public async Task InvokeAsync(HttpContext context)
    {
        if (!context.Request.Headers.TryGetValue(API_KEY_HEADER, out var extractedApiKey))
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync($"Api Key was not found in request. Please pass key in {API_KEY_HEADEr} header.");
            return;
        }

        var appSettings = context.RequestServices.GetRequiredService<IConfiguration>();
        var validApiKey = appSettings.GetValue<string>(API_KEY_HEADER);

        if (validApiKey != extractedApiKey)
        {
            context.Response.StatusCode = 401;
            await context.Response.WriteAsync("Invalid api key.");
            return;
        }

        await _next(context);
    }
}
3
  • How is the API key implemented? If you implement as Bearer token, you can use the built-in Authorize attribute on the controller(s) and use AllowAnonymous to exempt specific actions Commented Jun 21, 2021 at 15:15
  • @NoahStahl I have added the API key middleware to the question. There is no bearer tokens in this API as it is not designed to be user facing and is used for internal purposes. Commented Jun 21, 2021 at 15:36
  • OK. In this case the framework has no knowledge about auth, so none of the built-in attributes would come into play. The simplest thing is probably to add a conditional in your check to skip for certain exempt paths (context.Request.Path) Commented Jun 21, 2021 at 15:43

1 Answer 1

8

you can use HttpContext object to access endpoint and metadata like attributes.

var endpoint = context.GetEndpoint();
var isAllowAnonymous = endpoint?.Metadata.Any(x => x.GetType() == typeof(AllowAnonymousAttribute));

then add a conditional in your check to skip.

if (isAllowAnonymous == true)
{
    await _next(context);
    return;
}

Note: you should place your middleware after Routing middleware to use GetEndpoint extension method. if your middleware place before Routing middleware GetEndpoint extension method return null

app.UseRouting();

app.UseMiddleware<ApiKeyMiddleware>();
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.