Implementing API Key Authentication in ASP.NET Core

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody I'm Nick and in this video I'm going to show you every single way you can use to add API key authentication in your ASP Network applications so you can choose the one that works for you we're going to take a look at General approaches controller based approaches minimal API based approaches and I'm also going to show you how you can add Swagger support So when your consumer of your API or your system go to the open API Swagger page they can use the authorize button and provide the API key there so they can have the best experience you can provide I made a video like this all the way back in 2019 and a lot has changed since then so I want to have a new complete version for you so that's your One-Stop shop for API key authentication if you lack of content and you want to see more make sure you subscribe during this notification Bell and for more training check out Nick chapsters.com alright let me see what I have here I have a simple aspin core application and the most important thing to understand is that we're gonna use no third-party nuget package this is all built-in stuff the only packages I have are the ones that come with the template which is the open API so we can have Swagger support and really before I show you anything I want to explain the fundamental of how an API key authentication system works usually you have two approaches the first one is that service a wants to talk to service B and service B only wants to accept requests from authenticated services this is usually done in internal services in companies so service B has a static key that it accepts API requests on and service a needs to provide it either using a query string parameter or a header but of course other ways you can use to do Services service authentication but this is a fine approach the most important thing to understand about it though is that service B doesn't care that service a is calling it or service C is calling it or service D is calling it any service that calls it will use that single API key and the consumer doesn't really matter the other side of the story is when you have Dynamic keys and you can create keys for different consumers so if Nick is using the open weather map API for example then I can go in the API log in create an API key and then use that API key but the open weather map API no knows that I am Nick and I am rate limited I am monitored it knows that it is me so that's a different scenario in this video we're gonna cover this static version of the key because the dynamic aspect can be just plugged in using the exact same code so I'm just going to keep it as easy for you to follow as possible so you can grab the code from the description and do whatever you want with it now for video purposes I'm gonna store the API key in app settings but you don't want to do that you want to use something that is designed to store secrets and API keys for example AWS service manager or Azure key Vault or any other service designed to do that sort of thing but in this case I'm just gonna assess indication over here and have the API key the other thing I want to do is create a directory called authentication so I can have all my authentication logic in there and the first thing I'm going to do is create an off constant class now this will be a static class containing constants so I'm gonna have two things the first one is the path to the setting in my app settings search authentication and API key because this is Authentication and API key and the other thing is actually the header name I'm going to use to provide the API key because the approach we're going to use is use the X API key header to pass the key here you can use a query string parameter as well but I prefer the API key being on the header now first let's define an API key and I'm going to go with the simplest approach I'm just going to create a good over here use that I'm going to remove all the hyphens I don't particularly need them here and I'm just going to copy it and put it here so every request that will be authenticated will need to use this key and now I'm gonna go with my first approach which is the generic approach which is using a mid lure so I'm going to go ahead and create a new middleware over here called API key auth middleware now middleware has two main components you don't need to implement any interface which makes it a bit interesting of an implementation but what you need to have is a private read-only request delegate over here and usually you call that next because it's your way to call the next thing in the will pipeline in the request Pipeline and you inject it from The Constructor and then you also have an invoke a sync method that has an HTTP context parameter over here and this parameter gives you access to things like the request the response so you can write a response and so on now the first thing we need to do over here is to actually check hey do you have an X API key header so I can get the key invalidated if not I'm gonna tell you that the API is not there so we're gonna do that very simply by saying context request headers try get the value of the API key header name and if you did not find one then simply return 401 unauthorized and say API key is missing and that is it now to do the validation I actually have to get the API key from configuration so what I'm going to do is inject the private read-only I configuration over here and then pass it down here to grab the API key using the get value and then the section name or the path name of the options and of course you could have your own option containing the key or you can inject any logic here to call let's say a secret manager to load that key to do the operation that would go here and then the rest of the logic goes as you'd expect does the API key match the extracted one if it doesn't 401 invalid the API key if it does then simply use the request delegate and pass down the context to move to the next request in the pipeline so the only thing I need to do now is actually register the middleware and middleware is actually sequential so you don't want to have it before things like Swagger or maybe things like https redirection I'm gonna have it before authorization so I'm going to say app.use middleware and I'm going to pass down the API key of middleware and that's it I'm going to go ahead and just debug the API and first I'm going to remove the API key from the header so if I send a request now I'm getting API key is missing if I provide it but it's wrong then I'm gonna get invalid API key and if I provide the right one I'm gonna get the weather that's it that's how easy it is now this General approach the first one is great if you want to cover everything in your API behind this API key authentication however often this is not the case often you want more control so I'm going to start showing you how you can control it further by showing you another approach called an auth filter authorization filter we're going to go ahead and create an API key of filter over here and here you get to choose which interface you want to implement do you want it to be something that supports async then you want to go with I async authorization filter and then if you implement the missing members you get the own authorization async do you not need to be async like we don't need it in this video then I'm gonna say I authorization filter and you're going to get avoid version instead same thing though now like before we're gonna need this eye configuration so we're gonna inject it and what I'm going to do is simply copy the code as it is from here and show you the differences between the middleware and the filter so here we still have a context but this context is different this context it's not the HTTP request context you still have it in here so HTTP context with access to everything but you also have some things like filters actual description model State Route data and also result which is a nullable value this is very interesting because the way you return something from a filter is actually by setting the result you don't pass it to the next thing in the middleware you just say result is this and you return and you're gonna exit early so I'm gonna still use this HTTP context to get the header but instead of writing the response like this all I'm going to say is say result equals new unauthorized object result and that is it and I'm gonna copy the same thing over here use the invalid API key name and that's it now you don't call the next thing in the pipeline and in terms of code this is it that's all now there's two ways to work with filters the first one is to go in the controller the add controllers method and say filters dot add and add the API key or filter and this will be added for every controller you have in the system so if I say debug over here and I go back in then if I have the right key everything works if I don't have a key at all API key is missing if I have a wrong key API key invalid and unauthorized and that's it but that's one of the ways because now we still have the same problem that every controller has this filter attached to it so I'm gonna just comment it out in case you want to grab it and do something with it and I'm going to say builder.services.add scope because filters are scope the same way controllers are scoped and I'm going to say API key off filter now just by registering I didn't do anything but what I can do now is go to the controller itself over here and I have two options either on the controller if I want it to be applied to every action in it or the action directly I can go and say service filter type of API key of controller and now I have applied the filter just to this thing and just to prove it I'm gonna just quickly copy this and say whether to over here but have this not have the filter so I'm going to just quickly run this and I'm going to go here and again if I don't have an API key API key is missing if I have it but it is invalid API key invalid if I have it and it's valid then I get the weather but if I say whether 2 over here and I have an invalid key then that is not affected I'm still getting the thing if I don't include it then I'm still getting the thing because now I've used the service filter to apply it only on this action I can move this if I want over here on the controller and have it be applied for every action in the controller completely up to me I'm just gonna move it where it was and comment it out in case you want to grab it and do something with it but now I'm going to show you something very interesting with that filter you can actually go here and add the attribute type and say that this now also extends attribute and it's also an i authorization filter there's something very interesting with this nothing will break in the existing code in fact if I just have it here this will just work and go back here I can call the request nothing broke if I say weather then API key is missing everything is working but now I can actually copy this name remove this service filter and use it as an attribute directly we have a bit of a problem however configuration is injected so I cannot use it like this because I'm injecting the configuration so if you wanted to use it with this approach you'd have to actually get configuration from the HTTP context so you would say configuration equals context dot HTTP context dot request Services dot get required service I configuration and then you'd have to use it here if you do that then the API keyword filter is working I'm gonna go ahead and just build it and if you prefer this approach you can use it to have the exact same experience as you can see and again everything in the second action is not part of this on education now I personally don't prefer this approach because it makes mocking things way more difficult when I'm testing my filters so I prefer to use the service filter approach and pass it down like this but that's completely up to you I'm just going to show you both ways and you can choose these are basically all the simplest flexible ways you can use to apply this in controllers but what about minimal apis which is supposed to be the future well I'm gonna go below this map controllers method and I'm going to add the exact same logic but in a map get request which is that minimal API request and I'm gonna go here and show you that if I run this API and call weather mini then I can just call it it doesn't matter if I have an API key or not what's important to understand is that if I use the middleware over here then every authentication related thing in the middleware is applied to minimal apis because middleware is pipeline agnostic it just says I am in the pipeline and whatever is below me I don't care it can't be a controller it can't be a minimal API it doesn't matter however we cannot use the API key auth filter with minimal apis neither as an attribute nor as an i authorization filter that's a completely different type of filter for controllers so if I try to do it on a something like using the service filter thing over here and I just try to apply it on the delegate and I just quickly remove this and I run it then it actually runs as you can see it starts but if I try to call it it doesn't really do anything it just completely ignores the attribute so keep that in mind you cannot use your controller based filter with a manual API but that is fine because now we have endpoint filters specific for minimal apis so what we're going to do is create a new class called API key endpoint filter and I'm going to have that implement the I endpoint filter interface and now I have this invoke async method and it is async by default and I can have all my logic in here I'm going to turn this into an async value task and I'm going to start implementing so the first thing I need to do of course is again inject the configuration over here and the approach in here is an interesting one because it's a mix of sort of the filter and the middleware approach so in the end yes if you want to move on in the pipeline you're going to say return a weight next and pass down the context which is no longer the HTTP context it is an endpoint filter invocation context but it does if you look in here contain the HTTP context if you really need to but now if I add the exact same extraction and checking logic as before we don't really set a result over here we just sort of return using the results or the typed results over here and we say Okay accepted whatever we can say unauthorized so we can do this and that would work now one thing to point out here is that I can't actually pass down a message if I wanted to so I've actually made my own type that is unauthorized with a body either a string or a Json body I'm going to go ahead and just quickly create it so you can all see it I'm gonna call it an authorized HTTP object result over here and it looks like this so it has an object body if a body is a string it just writes it as a string if it is any other type of object then it serializes it and writes it as an object and that is it so what I'm going to return here is first return a new unauthorized HTTP object result API key missing and same thing here but invalid API key so now they have that I can go here and I can say add endpoint filter and I can specify the type so API key and point filter and now I can apply it on that item itself so if I go ahead and I run it then I can go here I can call it without one API key missing I can call it with the wrong one invalid API key I can call it with the right one it all works and this by the way will work the same if you use a group so if you have an app.map group and you have a weather group over here and you specify it like this and then you register the thing in the group and you register the endpoint in the group as well as then if I just quickly run this and I go back here this should now be weather forecast weather mini so if I call it as you can see it all works but if I don't have that API key API key missing but if I do have it and it is wrong API key invalid and that is it so everything in that group will be authenticated and really in terms of approaches that's it that covers everything controllers minimal apis General middleware everything is covered but there's one thing that many people are missing which is how do you add Swagger support because if I go ahead and I just run this thing over here let me just quickly revert the let's say the API key off filter on the controller level as well if I go ahead and I debug it and I use a Swagger interface and sorry if I blinded you then as you can see I have all my endpoints but I can't really you authenticate to call it I'm gonna try to call it but it's gonna say 401 I what are you expecting me to do so how do we add authentication support in Swagger it's extremely easy actually what I'm going to do is just go to the program.cs over here at the very top where you have the add Swagger gen and I'm gonna go into the London here where I can customize everything I want you really need three things the first one is a security definition and that looks something like this you just Define how you're accepting your security in this case I'm saying that the name is API key the name over here which represents the header is X API key it's located in the header and the scheme is API key scheme and that is it the type is API key next I need to define the scheme in the object so I'm going to have the scheme here it's a header API key and so on and then I'm gonna use that scheme into a requirement and then all I'm going to say is add the security requirement using that requirement that uses the scheme and that is it now exactly as it is is I can go ahead and debug it and if I go back to Swagger Knight refresh now I have this authorized button and I can pass down the value and the value here is this one with the missing seven in the end so if I go and I paste it and I authorize then now I can call all the endpoints as you can see and I'm getting the weather and if I don't have it I log out and I execute 401 that's it this is how simple it is so I hope you enjoyed this video I covered everything I think but if I did not cover something leave a comment down below and I will help you but for now that's all I have for you for this video thank you very much for watching special next to my patreon to make it videos possible if you want to support myself you can find the link description down below leave a like if you like this video subscribe the Bell as well and I'll see you in the next video keep coding
Info
Channel: Nick Chapsas
Views: 42,958
Rating: undefined out of 5
Keywords: Elfocrash, elfo, coding, .netcore, dot net, core, C#, how to code, tutorial, development, software engineering, microsoft, microsoft mvp, .net core, nick chapsas, chapsas, dotnet, .net, .net 7, .net 8, asp.net, asp.net core, api key, api key authentication, api key auth, api key auth .net, api key auth c#, api key auth .net core, api key auth asp.net core, Implementing API Key Authentication in ASP.NET Core
Id: GrJJXixjR8M
Channel Id: undefined
Length: 17min 57sec (1077 seconds)
Published: Thu Feb 09 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.