Protecting your API endpoints can be a daunting task and while there are many methods to protect endpoints, .NET Core offers a very simple approach which can also be integrated with the .NET Core Identity Framework. In this article, I’m going to discuss one approach I’ve taken to protect some API endpoints. I’m not going to delve too deep into C#, .NET Core, or the Identity Framework itself, but you should still be able to follow along if you’re not familiar with those.
First off, and this is optional, I’m going to extend the IdentityUser class to have a new property called “ApiAuthKey”. Since this is an optional step, I’m just going to show you what the new user would look like. You would need to either add the column manually to the AspNetUsers table or run Migrations so that the changes are applied to the database table.
Now, we need to update two pages within the Identity Framework, so you should scaffold the pages. Again, since this is an optional step, I’m not going to go into that too much. But after scaffolding the Razor Pages/Controllers & Views, we’ll need to update the Register and External Login pages/controllers so that when a new user is created, they’re automatically assigned an unique API Key. We’re going to keep this simple and use a GUID.
Now, whenever someone registers with your site via the Register page or through an External Login they’re assigned an unique key. If you’re using logging in your application, you may want to decorate the above ApplicationUser’s ApiAuthKey filter with [NotLogged]. You can do this easily if you’re using Serilog with Destructurama.
Now, comes the actual security part. We’re going to create a new class that inherits from the ActionFilterAttribute, let’s call it AuthKeyFilter.cs.
This class will allow you to decorate methods within an API/Controller with the following: [ServiceFilter(typeof(AuthKeyFilter))]
Before we go into the code of the AuthKeyFilter.cs file, we have some wiring up to do first. There’s not much, so don’t worry!
Open up the Startup.cs file and within the ConfigureServices method, we’re going to add three lines:
You should place this after registering your database context. Now, here’s the complete code for the AuthKeyFilter.cs file:
As you an see from the code above, we’re using dependency injection to get the database context for the IdentityDbContext and added something for logging.
Basically, what’s going to happen is whenever you decorate your method with [ServiceFilter(typeof(AuthKeyFilter))] it’s first going to try and get the remote IP Address. It then checks if the “AuthKey” is passed in via Querystring or in the Headers. Please note the extension methods used are optional as I’m using my own extension method library called BabouExtensions (this allows for you to do string.IsNullOrWhiteSpace()).
Once we obtain the key, we check the User’s table to ensure that it exists. If it doesn’t we return an UnauthorizedResult. If it does, we log it. As you can see, I’m logging the first 10 characters of the the AuthKey passed.
And that’s essentially it! There’s a super simple way to protect your API endpoints!