RESTful and HTTP APIs in Pyramid Transcripts
Chapter: Authenticated services
Lecture: Passing the API key
0:01 Now we have our users, we want to be able to go to our APi over here and when we do a request we want to pull this out,
0:10 so let's start by saying this is going to be an authenticated request here, the listing of all the autos, so we can add it to all of them, right,
0:17 we'll see there's a super handy reusable way to do this but for now, let's just print out, so far we've not needed this request,
0:25 we are going to temporarily need this here, and then we can get rid of it, we are going to printout request.headers,
0:32 so if I run this, let's go back to postmen and we'll just do a request against api/autos, notice we're asking for application json accept
0:41 so that should show up in our headers, well that was super unhelpful, wasn't it, let's do it like this, let's do it again,
0:53 there we go, force it to be standard dict, not something derived from dict, okay so we're passing the postman token which is unhelpful
1:02 but this you saw us set their accept header right there the user agent is postmen, the encoding and whatnot, right.
1:08 So these are the things that we're passing along from our client so let's go and actually figure out how to pass the API key here
1:19 so I could just try this, I could come along and this to a new key Apytest and we'll send that and let's see, does that show up— it does, right there
1:29 so we can put arbitrary headers in here ok there's a convention in the web around authorization so there's an actual authorization headering,
1:42 you see, postman is saying yep, there is one of these and there is some known formats around this,
1:47 so you'll see things like if it's blank, it's like username password basic c4 encoded I believe, you might see bearer that's often something like this,
1:57 if you're doing oauth, but what we're going to do is we're just going to say API key is 1 2 3, something like this
2:03 so we're leveraging a slightly more well known header here let's do this again, and now here's our authorization like that.
2:11 So we should be able to go to our headers and say get authorization, if I spell that correctly and restart it, we should just see API key 1 2 3,
2:20 okay, so now what we want to do is we want to get this, let me write it explicitly here,
2:30 and then we're going to move this into a much better place right, kind of like with our validation, then moving to view models
2:35 we're going to do something way better. So, let's just start by manually doing this, we'll say if not authorization,
2:43 if authorization is not in rather, request.headers we'll return response status = 403 permission denied, body no auth header.
3:00 Now we're just going to make sure that you're passing this, so let's go ahead and say well what happens if we don't pass this
3:06 boom, 403, no auth header, if we do pass it now we make it past this first step, cool.
3:13 Next, notice the format here, we have API key and then something else here so let's get that something else out, alright,
3:22 so we'll say parts equals this, grab the actual value, a cleaner way to do this might be auth_header =request.headers.get
3:38 and just go like this, so we don't have to get it twice so now we know we have it, let's go down here we can do a split on the colon
3:45 API:something that has no colons, we'll say if the length of parts is not equal to two return invalid auth header, something like this,
3:57 or let's say parts.strip is not equal to API key. Okay, so we can go check over here again,
4:09 put this as without a dash or whatever invalid auth header, put the dash back, all right, we're still going through, okay.
4:16 So the final thing to the look at here is we're going to have the actual API key is going to be parts.strip so let's get rid of this little print,
4:28 now, the goal is to go and get the user, so let's say user = repository find user by API key, and we pass the API key here
4:36 and we'll say if not user, one more of these return invalid API key no user with this account or something like that, right
4:47 whatever you want to have here. And then huuuh, if we pass all these through, we pass the header, it's in the right form,
4:54 it is the right value, we can find another database we should be golden, right let's test it,
4:58 this should fail because 1 2 3 is not in the database no user with this account but remember, I copied this, let me past it, get back in the clipboard,
5:05 let's set it to a real value, right, that's mike and I suppose we could even print out who it is,
5:11 let's just do a quick print listing cars for, list their name, right that's good, so come over here and let's do this, it should work— it does,
5:26 this API key is being passed in, and listing cars for mike, not for sarah, not for chloe, not for jeff, for mike, because this was mike's API key
5:35 if we chose a different API, we would get a different user. Let's be jeff, alright, so now we should be jeff,
5:44 still works but now we're listing cars for jeff, okay. So we're totally passing this across, how do you guys feel about this?
5:51 Do you like having this in the front of every one of your functions— I think this is dreadful, if I want to change what I call that header from
5:58 api-key to something else, there's so many reasons why having this not hidden away as a function is a bad idea.
6:08 Also, we don't want to necessarily make sure that people require to call it all at the beginning
6:14 and if they call it but they don't somehow return, like invalid response or whatever, there could be a lot of problems, maybe forgetting this
6:21 and having an unauthorized method when it was meant to be authorized; so what we're going to do next is we're going to improve this with a decorator.