And now we need to implement another strategy that actually validates that JWT so that we can use this
on all of our other routes where we want to apply authentication to.
So let's go ahead and open up our auth directory again and let's open up and create a new strategy in
our strategy folder called JWT dot Strategy Dots.
So this is going to be a new injectable class here.
We're going to export a class called JWT Strategy, which will follow the same pattern as our local
strategy.
We're going to extend passport strategy here from Nestjs passport, and this time we're going to pass
in the strategy from Passport JWT.
So recall that this strategy that we installed earlier will handle most of the work here.
We just need to supply some configuration inside of the constructor here.
So in the constructor itself, we're going to need to get access again to the config service here.
So let's go ahead and inject the config service as well as the user service.
So let's go ahead and inject the user service here.
And now inside of the constructor we're going to make a call to super here.
And now there's some options that we need to configure.
First property we're going to configure here is JWT from request.
And what this is going to do is it's going to actually specify where on the request object that the
JWT lives.
So by default, this might be a header value, but in our case, we know that the gut is actually a
cookie itself.
So let's go ahead and specify that here by calling extract JWT from Passport, JWT, and then we're
going to call from extractors on here and supply an array where we will provide a function that gets
the current request.
So the request object here, you know, will actually be from Express.
So go ahead and import request.
From express top and now we specify where on the request object where the GDB lives.
So in this case we're going to look under request dot cookies, dot authentication, which is where
our JWT should be if it was correctly set on our auth service.
Now that we've actually told the strategy where the JWT lives, we need to supply the secret or key,
which is going to be the JWT secret value that it will use to decode it.
So of course this will be the same key that we use to sign.
The cookie is going to be the same key we're going to use to verify this cookie so we can use the config
service here and call config service dot get JWT secret.
So now we've configured our constructor, we're going to have that async validate method again, where
in this case we're going to get the user ID.
And the reason we're getting the user ID here is because after the JWT is decoded, the token payload
used when creating the token is going to be supplied to the validate method here.
So if you remember, if we go to auth service when we actually created the token, we had this token
payload here where we included the user ID.
So let's actually go ahead and define this as an interface here.
So I'll create a new folder here called Interfaces and we will add a token payload dot interface, dot
ts, and we'll export this interface called token payload where we know we have the user ID of type
string.
So now in the auth service we can actually specify the dedicated interface and we'll do the same thing
here in the strategy.
So after this JWT is decoded, we get that token payload in the valid method which this strategy will
take care of all for us.
And while we have that token payload, it's now a responsibility to check to see if the user on that
token actually exists.
So we can easily do that by calling this dot user service, dot get user.
And I'm going to pass in an object here where we supply the underscore ID and pass in the user ID.
So of course we're going to have to implement this.
So let's go in to the user service and implement a new method here called async get user.
And inside of this route here, we're actually going to specify a new DTO file.
So let's specify a DTO to get a user.
So in the folder I'll add to get user DTO and we'll export a class here called Get User DTO here we
will specify that the user will pass a string to get the user.
We'll use class validator to make sure that this is a valid string here.
And also this is not empty.
So now in the user service we'll specify that we have get user, DTO type, get user DTO, and then
we can call this DOT users repository dot, find one and pass in the get user DTO.
So now if we go back to our JWT strategy, you can see that we are correctly getting the user here after
we decode the token.
And if the user doesn't exist, of course we know we will throw a 404.
So now that we have the JWT strategy, let's go ahead in our guards folder.
And this is going to be very similar to our local off guard.
We're going to export a class here called JWT Auth Guard.
That's going to extend auth guard from Nestjs passport and we will just pass in JWT here.
So now we can test out our JWT auth guard and JWT strategy by going into our users DOT controller.
And so I want to create a new route in here, a get route that will actually just return the authenticated
user.
And this is going to be very easy for us to do.
So this is going to be an async get user route and we actually don't need to supply any args here.
Instead, we can actually pull the current user off of this route, which we know will be of type user
document here and all we're going to do is actually just return this user back to the caller.
And now all we need to do is actually run the use guards here and supply the JWT auth guard.
So just like the local strategy in the JWT strategy, whatever we return from this validate method still
gets populated on the request object.
So as soon as this guard is run, we have the user on the request object and we can simply return it
back to the caller without having to do anything else here.
And lastly, make sure in our auth module here, just like we did for the local strategy, we add the
JWT strategy in our providers array here.
So now in Postman, I'm going to launch a get request at localhost 3000.
One slash users to get my user here.
And if I launch this request off right now, you can see we get a 401.
Unauthorized, which is great to see.
We haven't actually included any valid JWT with this call.
So we expect that it is unauthorized and this is going to be the same guard and process we apply to
any protected route.
If we don't have a JWT, we will get that 401 back.
So to get a JWT, I'm going to launch a post request at localhost 3001 slash auth login.
And this is going to be for a user I've already created here.
I have the credentials in the body.
I'll go ahead and send this.
And so now we have the JWT set on our cookies here.
So now if we launch a request at users to get the current user, you can see we're still getting a 401.
Unauthorized even though we're actually sending the auth cookie with this request.
So why is that?
Well, this is because right now we're not actually parsing the incoming cookies on the request.
So in order to do this, we're going to go ahead and install a new package.
So let's go ahead and NPM install a package called cookie parser.
And what cookie parser is going to do is it's going to parse incoming cookies and add them to the request
object.
I'll also go ahead install the development dependency for the cookie parser types here as well, and
then we can go ahead and start our containers back up.
So now in our main.ts for our auth project, what I want to do here is I want to import Star as cookie
parser from cookie parser.
And now what we're going to do is before we add the validation pipe here, we're going to call app dot
use.
So this is going to be a middleware and all we have to do is call cookie parser here as a function and
automatically all requests with their cookies will be executed through this middleware here and all
incoming cookies will be now parsed.
So now inside of Postman, now that we've set up cookie parser, if I launch this get request when we
launch it, we see we actually get a 200.
Now that this request was successful and we are actually getting the user back here because of our JWT
authentication working properly and our cookies are getting parsed.
So we have implemented full end to end authentication.
With JWT, we have an auth guard we can use anywhere in our application to lock down our routes and
we are ready to move on.
So let's go ahead and do that in the next lecture.
Right now in our user service, when we create a new user, we're actually currently allowing multiple
users with the same email to be created, which could be leading to issues when we actually want to
verify the user by that email.
So let's go ahead and actually implement some validation to ensure that only a unique email can be used
when creating a user.
So before creating this user, we'll call await this dot, validate, create user DTO, and then we'll
have a private async validate, create user DTO here, which of course takes in the create user.
DTO I'm going to open up a try catch block here and inside of the try we're going to call await this
dot users repository dot find one and look up this user by the email in the create user DTO.
So if this user does already exist in the repository, we know that we're going to throw a 404 error
and end up in this catch block.
So if that's the case, I actually want to return right away and exit this method because if the user
does not exist, that means this crazy DTO is actually valid.
So we can just leave the catch block and create the user.
However, if the user did actually exist and we didn't trigger an error, then I want to throw a new
unprocessable entity exception where we say the email already exists.
So now if the user was found, we throw an error here because the user should not exist with that email.
So now back in Postman, if I launch a post request to create a new user, I will send this off here
and we can see we are throwing an error because this email already exists.
So this is exactly what I expect to see.
Now, if I change the email to a unique email, we can see the user gets created.