Generating Tokens10:34 with Kenneth Love
No one wants to send their passwords around in plain text all the time. Giving users a safe and secure token to use will make them feel better.
Sending usernames and 0:00 passwords in plain text across the wire isn't the best solution? 0:01 I know I don't feel safe doing it and I'm sure you don't either. 0:05 So let's give our users a safer way of sending most of their requests 0:08 by creating a signed token that they can give back to us 0:12 to prove they are who they said they are. 0:15 So, I think before we start on tokens, 0:18 I wanna make sure that I can still get a list of courses. 0:20 So let's run the app. 0:23 Okay, cool. 0:26 And if I come over here, and I do a get on, users won't work. 0:29 So we'll do one on courses. 0:35 Send that, we get no courses, of course. 0:39 Let's try to post one. 0:42 Let's dump all of these. 0:48 We'll send the new one here, we'll say that title 0:50 is Django Basics and we'll say the URL is 0:55 https://teamtreehouse.com/library/django-- basics. 0:59 Can you tell which things I know the location of the best? 1:05 All right so let's try to post that. 1:10 And we get back nothing, right? 1:14 It didn't actually work. 1:17 It didn't go anywhere. 1:19 We get back to 200 okay. 1:21 Which is kind of funny. 1:22 That we get back to 200 okay. 1:23 It should not have done anything. 1:25 If I was to do a get on this. 1:27 I should see nothing. 1:29 Okay. 1:30 So what if we go ahead and send it through some auth. 1:32 So let's do basic auth. 1:36 User name is Kenneth Love. 1:38 Password is password like we said before and I'll send that. 1:40 And now notice I get back actual data, so that's pretty cool. 1:44 I don't get this unauthorized thing. 1:48 But it didn't let me do anything. 1:50 Nothing came through. 1:52 For doing tokens you might be expecting that we need to install 1:53 another package and all this stuff. 1:57 But we actually don't need one. 1:59 Flask has a dependency called it's dangerous. 2:01 Which does all of the token work for me. 2:03 These tokens are actually known as JSON web tokens. 2:05 I'm gonna link to a really great breakdown of them in the teacher's notes. 2:08 And also of course the docs for it's dangerous. 2:11 Before I generate the tokens, though, I want to set up the token auth. 2:14 So I'm gonna add all of that into auth.py. 2:18 We've gotta add two more imports here. 2:21 We're gonna import HTTPTokenAuth, and we're going to import MultiAuth. 2:24 So just like with basic Auth, we're gonna do token_auth = HTTPTokenAuth. 2:29 And I'm gonna to enter a scheme here that's going to be called token. 2:36 Schemes are kind of like domains, areas where a thing is appropriate or applies. 2:40 When we're doing this basic off, if you were to look at, sorry not there, 2:46 headers you would see this authorization thing here has the basic. 2:52 That's the realm or the scheme is basic. 2:57 So for us we're going to call it token. 2:59 And then we're going to make instead of basic off here, 3:02 we're going to do multi off. 3:05 And we're going to this is made up of token off and basic off. 3:07 Kind of the reverse of the location thing for the APIs multi off looks 3:11 at the first thing first so it tries token off first and then it tries basic off. 3:17 And if you don't want to use token you can leave this blank and 3:22 I do believe it defaults to bearer and then there's others you can set that, 3:24 maybe a certain client expects a certain thing, okay. 3:29 So when I have both types of off I want to have that all set up. 3:32 Now I do you have to tell the token off 3:35 how to verify a token just like I had to tell basic off how to verify password. 3:38 So let me write that function real quick. 3:43 So, token_auth.verify_token, 3:46 verify_token, and we're gonna get a token. 3:51 So user = models.User.verify_auth_token, and we're gonna pass in the token. 3:55 If user is not none, so if we get back a user and 4:03 it's not none then g.user= user and we gonna return true. 4:06 Otherwise we're gonna return false. 4:13 Sorry you probably thought that function was going to be more interesting. 4:16 It is actually pretty interesting though we have to go add this verify 4:20 off token though to actually make it interesting. 4:24 So let's hop over here to our models.py. 4:27 And this is where we're gonna create this new method. 4:29 So first of all up here. 4:32 We have to add from it's dangerous. 4:34 And we're gonna import a couple of things here. 4:37 We're gonna import TimedJSONWebSignatureSerializer, and 4:38 we're going to call that Serializer, because I do not want to type that. 4:43 And then we're also going to import BadSignature, and SignatureExpired. 4:48 All right, so now inside of class user which this is one of the more 4:56 interesting classes I think I've ever built here here at Treehouse, 5:00 I'm gonna add another static method down here. 5:04 And I'll add it above this one, just so that static method, 5:07 set password, and verify password can stay next to each other. 5:12 So, static method. 5:15 There is no underscore in that, there we go. 5:18 And we're going to call this verify_auth_token, and 5:20 we're gonna pass in the token. 5:23 So, serializer = Serializer, and this is where we need to 5:27 do config.SECRET_KEY, cuz remember we got our SECRET_KEY over here. 5:32 And so we're going to try, data equals serializer.loadstoken and, 5:39 with the exception of, signature. 5:47 Expired, bad signature. 5:52 We're gonna return none. 5:58 Otherwise user is equal to User.get. 6:01 User.id is equal to data id. 6:05 Cuz data's gonna have a key in it named id. 6:08 And we're gonna return that user, and 6:10 remember like here we are returning this user, and if we look over here this is 6:13 going to get a user so that user ends up being right there. 6:18 Otherwise we are returning none, because right here we return none. 6:22 That's why we check against none. 6:27 So now we actually need to make the token. 6:29 So this is pretty straight forward. 6:31 Thankfully I'm gonna put this one down here, 6:34 because it has to deal with a particular user. 6:37 So, we'll say generate_auth_token. 6:39 Self, and then when it should expire. 6:43 By default I'm gonna set it to 3600 seconds. 6:45 So, one hour. 6:48 So, this one's a timed one, you can do a non timed one or you can make your 6:50 expiration super huge, like it expires in a month or a year or something like that. 6:53 So, serializer = Serializer(SECRET_KEY), 6:59 which should come from config, and 7:04 expires_in is equal to this expires argument. 7:08 And we're going to return serializer.dumps, and 7:14 we're gonna set the key of id to the id of the user that this being called on. 7:17 So this is pretty similar to the verification method, 7:24 just the inverse of it. 7:26 Or make a serialiser instance with the secret key. 7:27 I want the tokens to expire all that and 7:30 like I said I'll link to the it's dangerous notes. 7:33 So you can see more about these serializers. 7:35 Something else to point out is that if you've used the JSON module before this 7:37 .loads and this .dump should be pretty similar, it's actually load string and 7:42 dump string so, very close to the JSON module. 7:46 Okay there's a lot to do and 7:50 I still don't have a way to actually give a user her key. 7:53 So how we do that? 7:56 I'm actually gonna do that over here in app.py. 7:57 I could do this on the user resource but I kind of want to do this in here to 8:00 show you how to add end points that aren't part of resources, but look like they are. 8:05 And also just because it feels kind of odd doing this on the user resource. 8:10 All right, so I need to import G and jsonify and then from off import off. 8:16 And then, we're gonna to make a new route down here. 8:25 So app.route, api/v1/users/token, 8:29 methods equals, I'm only gonna allow one method, which is GET. 8:36 And then this is also login_required. 8:41 And we're gonna get_auth_token and we're gonna 8:44 say the token equals g.user.generate off token. 8:49 And we're gonna turn jsonify token token.decode as ascii. 8:54 Cool. 9:03 So we have to generate the token on the user. 9:04 And we're gonna send it back as a JSON response. 9:09 Hence the JSONify. 9:11 We have to decode it into ascii first, just to make it safe to send across. 9:12 Of course we want to make this a login required. 9:18 Because we have to actually have a user to give the token to. 9:20 All right. 9:23 So, I should already be logged in from creating this. 9:25 So, I should be able to go to GET, and users/token, hit send. 9:28 And there's my token. 9:37 So that's pretty cool. 9:39 And now I can grab this. 9:40 I can go over here to authorization, say no off. 9:42 Go to headers, change this here to token and paste in my key right there. 9:48 And now, I've got my token which is cool. 9:55 And my token didn't change, 9:58 if you notice my token stayed the same here when I requested that again. 10:00 I’m still authenticated. 10:03 I'm all set up and I’m ready to do a lot more stuff. 10:05 If you give them a token that doesn't timeout, 10:09 you could provide them a key when they register their account. 10:12 Then they can just send that back every time as their authentication. 10:14 This eliminates all of the password submitting, 10:18 other than when they sign up for the first time. 10:20 But makes your token a little less secure because someone 10:22 else could get a valid token and be able to make submissions forever. 10:25 Weigh the pros and cons yourself and 10:29 pick whatever you think is the better solution for your particular project. 10:31
You need to sign up for Treehouse in order to download course files.Sign up