In a typical ASP.NET Core web service request pipeline, you'll find authentication pretty early on, then some authorization and finally the execution of the desired action.
For most cases, that's great. However, you surely have encountered situations where all you needed was a simple yes/no validation - often for services that don't return stored information but simply perform some action based on your inputs. Integrating that in full-blown approaches like OpenId flows can often be cumbersome. Imagine you'll want to store your build artifacts on some web service you own - passing a single, secret Api key through your CI pipeline is much easier than setting up complicated, multi-step authentication setups.
Generally speaking, when your action does neither retrieve information nor alter existing data, you're safe to use an Api key.
With ASP.NET Core, you'd do that by creating a custom Policy that guards certain actions. These components are essential:
- An IAuthorizationRequirement, which defines the requirement
- Accompanied by an AuthorizationHandler, which checks the requirement
- A bit of plumbing in your app to make them work
Let's walk through the implementation!
First, define an ApiKeyRequirement:
It's an implementation of the IAuthorizationRequirement interface and simply stores the list of all valid Api keys in-memory.
The corresponding ApiKeyRequirementHandler is responsible for evaluating incoming requests for their compliance with the requirement, in this case by checking if the Api key is given in the request header.
This has to be wired together in your Startup class. First, you have to add a custom authorization policy with a unique name - ApiKeyPolicy in this case. An instance of the ApiKeyRequirement is added to it. Secondly, you have to register the ApiKeyRequirementHandler in your service collection.
When everything is correctly set up and configured, you can now reference this authorization policy in your controllers:
Please consider this post simply as an example! For production use, you'd want to implement at least storing the Api keys hashed in your database, with the option to revoke them and with some connection between users and Api keys
PS: If you're looking for an approach to implement custom authentication, you can take a look at how that is implemented with using Http Basic Authentication as example.
Edit, 30.01.2020: It's always great to get feedback, especially when a blog post was able to help somebody! Valentin from randommer.io used this example to quickly secure their API with keys.