Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Preview
Start a free Courses 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.
Related Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign upRelated Discussions
Have questions about this video? Start a discussion with the community and Treehouse staff.
Sign up
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 auth,
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 auth here,
3:02
we're going to do multi auth.
3:05
And we're going to this is made
up of token_auth and basic_auth.
3:07
Kind of the reverse of the location
thing for the APIs MultiAuth looks
3:11
at the first thing first so it tries token_auth
first and then it tries basic_auth.
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 auth
I want to have that all set up.
3:32
Now I do you have to tell the token_auth
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
auth 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.loads(token) and,
5:39
with the exception of, SignatureExpired,
5:47
BadSignature.
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 serializer 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 auth import auth.
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_auth_token.
8:49
And we're gonna return
jsonify({'token': token.decode('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 Auth.
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 upYou need to sign up for Treehouse in order to set up Workspace
Sign up