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