Note: a lot of people are getting the error “request.isAuthenticated is not a function”. Please note that I explicitly mentioned in the video that it will not work until you properly setup sessions. If you run into that error, KEEP watching! The problem will resolve itself once you have the full setup, don’t stop at the point of error. If you watch the rest of the video and still have this problem, double check that you properly configured and registered your strategies and guards exactly as shown in the video.
Any chance this can be added as an annotation to the video at that point? I fell into the same trap! Otherwise - awesome video. Keep up the great work!
And maybe something I am missing is some notes about the logout. Currently I am calling .logout() on the request AND calling session.destroy(). Maybe only the last one would be sufficient as it removes the complete session anyways ;-)
A problem I encountered: if you use argument names other than 'username' and 'password' for local strategy, you must specify them as options in local.strategy in super({ usernameField: 'otherName1', passwordField: 'otherName2' }). If you don't, it won't even throw any errors, you'll just keep getting a 401 Unauthorized error. This drove me insane. Hope this helps others avoid this mistake. But great tutorial regardless! Content like this makes the internet amazing.
Hey Marius, just passing by to thank you, your video format is awesome. I love how you explain everything while showing the documentation. It really adds to us as developers, so that we know like "oh, so the information was here all the time!". It particularly helped me a lot. Keep up the good work!
It would be terrifically useful if you would build the client side login flow that connects with the JWT strategy. This tutorial was really clear and concise.
Thanks, will consider it! For the most part the client-side is really just all about managing/storing that jwt somewhere and making sure it’s included in the headers of each request to your API. I’ll try to make a video about it sometime.
Even today i remember how i asked the question below the similar type of video about jwt and you reply back really fast althought your video was already great. As i see you still answers the questions and its impresive.
Thanks! Will consider a specific video on that topic. Not really much to it though, sign-up is basically almost the same as login, but obviously you’d be adding to a db table of users, and removing is simply deleting that record
@@mariusespejo thanks for this video Marius i'm studying jwt Login authentication with nest.js, react too. complete authentication tutorial(refresh token, logout ...stuffs) will be very helpful for me I want you to refer to making a video for this. Thanks!
Great video Marius! You made clear a lot of points around authentication that were a bit confusing to me. Could you possibly make a video about authentication using JWTs with NestJS and GraphQL (code first)? Thanks again!
Well there’s logic to why it would not be authorized, that’s exactly what guards are for. Do some logging to find out why…e.g. maybe you tested with expired/wrong token, maybe user wasn’t found, maybe your sessions (if you’re doing sessions) aren’t set up correctly etc. etc. it’s not magic there are simple boolean logic behind your guards that determines does the request move forward or not, you just need to figure out the why and see if you made a configuration mistake
60 seconds is obviously an unrealistic expiration that was only used an example.. you should decide what makes sense for the security of your application. If you want it to automatically renew for the user you can do that with refresh tokens, not sure if the passport strategy does that automatically. Anyways otherwise yes you’d have to have them login at expiration
Great work ! , but I was wondering , it's too many steps I think I couldn't all of these from my memory , I think it's hard at first and it's okay if I followed the documentation to implement it .. what's your opinion about that ? all love from Egypt
I mean unless you do this type of work often it’s not really something you would memorize. For most applications you probably only set up auth once and adjust it a few times. I would definitely suggest having the documentation as reference. It’s ultimately the fundamentals of auth and session management that you need to understand and know well, then you can always reference docs if you need a refresher
Hey Marius, old video now ik but still asking, do we need to have a JwtGuestGuard (e.g. for LOGIN route) ? If so, we need to recode a canActivate method right ?
To be more accurate, what I mean by GuestGuard is some kind of Guard that says « hey your token is still valid I can’t generate you another one / your token is missing/non-existent, I’ll generate one for you »
And btw any good practice to invalidate a user ? Maybe some kind of fullstack app would be cool to make a video of :D enjoyed your work as always tho ! :D
Hey Abriscout, sorry not sure I’m understanding the question. Did you watch the video in full? I believe I did cover having a guard that checks for the existence of a jwt on any routes that you protect, but that wouldn’t be on a login route. Not sure it makes much sense to check for a jwt on a login route when the login itself typically would generate the jwt. It is not the guard’s job to generate tokens… it’s purpose is to simply decide “should I let this user proceed or not”. E.g. it could check if the token is invalid or perhaps it’s expired, then it can respond with a status 401/403 to inform the client “hey you need to login and get a new token”. Which is why again, doesn’t make sense to check for the token at login, because you know they NEED one if they’re calling login. I think what you might be thinking about are refresh tokens, which are meant to automatically allow a client to get a new access token, basically extending the life of the session without needing to login again. As for your second question, there isn’t really a great way to invalidate a jwt…you’d have to somehow track the id of that token and maintain some kind of block list. This is also generally why you want access tokens to often have short expiration. If you were using sever-side session however, then you’re in full control with every session object, you could simply just have your store remove a session and that would effectively invalidate a user
@@mariusespejo Yeah I was confused by so many things, and then I discussed with devs that have show me some ways of how to do it. My question was not very clear, but basically it was about preventing user that is already logged in to access the login route :D Thanks !
Not really sure it’s that beneficial to do something like that. What if you wanted to allow multiple logins across different browsers/clients? The client app should be designed in such a way that it knows if the user is logged in (to prevent access to the login form and instead show logout button, for example). If a user somehow tries to login again then the client app should simply know to discard and replace any existing token, wherever it may be storing it. Or if you’re interested in some kind of invalidation then keep track of all created token IDs server-side and if the user logs in then invalidate any existing tokens they already were provided. Basically there are ways around getting the proper expected behavior without needing to restrict the login route
I used to do backend things on ruby on rails, when we want to update something we use PUT/UPDATE verb which is pointed up to the update method, how do you do that where if the method it's tied with the verb decorator? or is it possible to do something like this @put("users") @patch("users") in the same place? thank you for your content
I’m not sure that you can do both verbs in one like that, however assuming the bulk of your business logic is on the service/provider then it’s not much more code to add an extra method on the controller class and just reuse the same service method
Can’t really think of better name than that though. Fyi in nest you can also create a custom decorator like @User() which can be set up to automatically give you the value of req.user
When I finish the local strategy without tokens or jwt first, I constantly get a 401 Error and that I am unauthorized, do You maybe know why and can help me out?
@@mariusespejo I just checked my code and I did all as shown in the video and have basically the exact same code as in the video, but it still wont work.
And you’re able to log out that you’re getting a user back? Did you verify that the validate method is getting invoked? Is the strategy actually registered as a provider in the auth module? Those are some steps to debug. It’s important to have a fundamental understanding of how passport works and how it’s used in nest, and where might your errors be. Local strategy when done correctly should be able to give you back a user with the match username password.
The gist of it is that you need to store your refresh toke somewhere, e.g. perhaps in your session store Every time your service needs to use the access token, check if it’s expired and if so refresh it using your stored refresh token. What the refresh request looks like differs depending on your identity provider, but usually it’s just a POST request with your refresh token attached
@@mariusespejo it is clear for me, thanks. but just imagine that you have at least 2 tabs with one user session and create several requests at the same time. the first request recieves 401 or checks an access token's expiry and tries to refresh one & renew in a session. it can take several ms. The parallel request tries to do the same thing and uses already expired access and refresh tokens and recieves an error "Token is invalid" . Maybe there should be smth like a lock mecanism. Or this script is wrong in the first place. I think it seems to be a great topic for the next video)
Yup will consider a follow up video. That’s definitely a valid edge case, there are several different ideas e.g. perhaps proactively check token expiration on an interval, not just on requests, or maybe flag the session to mark it as “refreshing” (similar to your locking idea) etc.. I would first consider though how likely that scenario would really happen for your use case. I can’t imagine refreshing really takes that long. Also something to consider is that in your scenario would it not simply just refresh at both requests? Meaning the second would just overwrite the token update of the first. If you make sure to wait for the refresh to complete on any request then I don’t see any real conflicts. Except for maybe when refresh tokens are rotated and become invalid, but again we’re talking about milliseconds here
@@mariusespejo however this edge case is likely to happen. I would love to see your realization anyway. Maybe there will be some tricks or tips that could help me out!
Is it required the we use 'username' & 'password' as the fields and not 'name' ? I get Unauthorized when I use name instead of username, (I've also changed property for comparison)
Very good job on this one! i decided to go with session auth for my application and it works just like promised with insomnia and postman. I'm currently setting up a frontend with angular and do now face a problem. The Session Cookie is visible in the chrome dev tools network tab, but the cookie is not set at Application > Cookies. Can some one help me please (didn't find an answer on stack overflow)
@@mariusespejo thanks a lot for the reply! i had to intercept the outgoing requests from the angular app and add {withCredentials: true} and changing origin: '*' to allow-origin: 'mything' as well as allow-credentials: true in the BE. Otherwise the cookie is not set in FE nor shipped with the Request or it results in a cors error. I should have mentioned, that BE and FE are not running under the same domain, my bad, sorry. But thanks again for your quick reply! You are doing a serious job here and i didn't find anyone who comes close to your tutorials (sound quality, speed, explainations) Thanks alot for that. best regards!
@@leo-3r i changed to jwt in the mean time. The reason is, my system is deployed to firebase and app engine and gcp does strip all cookies for security reasons. (There is a specific token name that should work though, but it did not for me, so a switched to jwt) So i am sorry, but i cant tell you how i made it work back then
You likely have services depending on each other.. it’s generally best to separate concerns as much as possible, e.g. I would not add /login inside your user controller. It’s better to do that in a stand-alone AuthController
@@mariusespejo A Company has Employees, Employees have Company. Then how you'd take this? This roadblock is at module-level, not just Service. Can you do some real-world app? There's someone who did Facebook clone end-to-end, not just small bits of everything and hopefully someone is clever enough to piece things together.
You can resolve the circular dependency itself if you’d like: docs.nestjs.com/fundamentals/circular-dependency But the point is to avoid it in the first place. I can’t tell you how exactly to do that, you need to understand your own dependency tree. I don’t see how this has anything to do with auth (the topic of this video)
@@mariusespejo I just mentioned that since we're talking about circular dependencies. Maybe "circular" is more on the negative side, I'll just put it as "two-way relationship", books-author, company-employee, library-books, hospital-patient and whatnot. I'm sorry if I got over excited and left my manners somewhere, but I had a great time learning the basics. So, great video. And so, would you please make a more advanced tutorial/demo -- something like a Facebook clone would be nice, or some website that is relevant today and of course with the use of this technology. Thanks in advance!
hi @Marius Espejo thanks so much for the tutorial. i keep on getting this error ERROR [ExceptionsHandler] request.isAuthenticated is not a function. what do I do ?
IsAuthenticated specifically comes from passport, that means there is something missing in your configuration. Did you set up express-session and did passport.initialize() and passport.session()? The order of those 3 things is important. Finally did you add the serializers and registered it in your module?
@@mariusespejo my error come before "Session setup", I followed your timestamp until "is.authenticated()" fault. I did replayed your vid 2 times but still have this error
I mean updates ideally are going through your api/controller if it’s user driven. If you don’t want to pass in the ID then you have to already have it in session store. If it’s just the system making changes then just trigger logic to update the record in database/session. I would suggest posting a more detailed question in stackoverflow
Not on github at the moment sorry, consider following the tutorial from scratch, it honestly won’t take the long, most of the video is just me explaining the details
The best tutorial i watched so far. Author tells the info clearly and without any useless data. So, i want to say that i was here when the num of followers had been 7k
Thanks a lot Marius! for Authentication session. Very well crafted beautifully explained. Just 1 suggestion if you could put this session over git. Would be great to look at the code and get relate it post watching video. Keep up the good work!!! All The Best!!
Thanks for spending the time explaining each part and drawing the parallels to his we would do it in express. Really helped me understand how to accomplish session auth. Felt a bit lost when the docs only covered JWT auth and all the tutorials I found were showing me the code to make it work... But not why it worked haha
What about an email instead of a username - I never use usernames with my applications. It doesn't work by just switching username to email... but it doesn't take much more work either, just a simple mapping object in the right place. ```export class LocalStrategy extends PassportStrategy(Strategy) { constructor(private authService: AuthService) { super({ usernameField: 'email', passwordField: 'password', }); } async validate(email: string, password: string): Promise { const user = await this.authService.validateUser(email, password); if (!user) { throw new UnauthorizedException(); } return user; } }```
@Dev Guy I read the documentation first and in the span of 4 days, probably 100 times :D I actually started the project because I loved the documentation, its just on spot, with a few missing parts :)
Docs are definitely very good but it’s not always intuitive to everyone. Simply saying just read the docs is like telling people don’t go to school just read the text books….
@Dev Guy I looked at and read the documentation from Nest and Passport. The main problem for me with the documentation is Nest is all classes and Passport documentation show you how to configure the different strategies in ES6. This video is literally the only resource I've found (and I searched for over a week) that explains that (a) passport is initiated when it is included in the correct provider array and you do not need passport.use() as explained in the Passport docs and (b) the UseGuard is registering the strategy and there is no need for passport.register(), again, as explained in the Passport docs
If you have this error "ERROR [ExceptionsHandler] request.isAuthenticated is not a function" you should return request.isAuthenticated; instead of return request.isAuthenticated() at the authenticated.guard.ts file
I highly appreciate you going throug the code roughly and also briefly explaining the NPM packages which you're using / recommending. It's really fun coding along and learning in this video!
Thanks for this tutorial, I went through the NestJS docs a few times and tried to set this up myself but there was always something wrong. Your vid helped me finally get it all working!
Thank you so much for this tutorial, it helped clear up so much of my confusion. All the examples of different Passport strategies are written using ES6 modules, but the documentation for Nest is with classes. Your video helped translate the difference and finally got my code to work. Very clear and well explained --signed a junior developer that only learned ES6 Javascript in my bootcamp XD
Hi guys, i am stuck in the chapter guard to check if user is logged in. It is an error said "request.isAuthenticated()" is not a function. I console log the keys of request object and realize that the object dont have the isAuthenticated isUnauthenticated ,user. Any suggestion guys ?
@@mariusespejo i have checked every step very clearly but can not figure out which step that i missed. Googling for days and have no hope man. The local strategy work as the video. But the authenticatedGuard implements CanActive not working. Do you have any idea for it ?
Did you actually setup sessions? Please note that in the video I explicitly said the guard won’t work until you actually have the sessions in place. That along with actually having the full passport local strategy working and correctly registered is what’s needed. Make sure to watch the rest of the video and don’t just stop at the point of error
@@mariusespejo My bad.that is the missing piece . i have finished following your tutorial. that really helpful . thanks for your answer and making such a good video. have a nice day
Why people are using sessions? In both approaches the client side must securely save the “cookie” or the “jwt token”. The main difference is that in case of the JWT approach the server does not need to maintain a DB of sessionId for lookup
It’s a matter of where you want to store the session…. In a store or in jwt… note that if you have a lot of data for your user session having all of that in a jwt/cookies would be impractical, that’s just extra data you’re sending over the wire. So it depends on the use case. Also server-side sessions are significantly more secure in my opinion, you don’t have to worry about tokens being intercepted (which again will have some user data on it)
Hello, I have covered the first 30 minutes of the video, I keep getting this when using postman TypeError: Cannot read properties of undefined (reading 'validateUser'). I do not find the error, I have checked the documentation
That’s a bit of a loaded question that is not simple to answer in a comment. First of all there are several strategies that depends a lot on your infrastructure, your identity provider, etc. Next the “how” again will depend on the strategy. I suggest spending some time reading about it