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