John is a member of the NestJS core team, primarily contributing to the documentation.
Note: You can find all of the source code from this article...
For further actions, you may consider blocking this person and/or reporting abuse
Yes thank you @johnbiundo
Please share more of your knowledge, best practices and guides on NestJs and authentication. Nothing is more important, all other features of the framework isn't useful before you have authentication going. I know I struggle with it a lot, I and I think others might too. So long knowledgeable articles are most welcome.
Thanks Christian. I do plan more articles on this topic. Let me know if there are particular areas you'd like to see covered!
dev.to/umasankarswain/how-to-updat...
That's really helpful article, thanks for it! It would be great if at least parts of it got integrated into Nest's docs.
Following all the steps described I managed to get auth+sessions work. But one thing bugs me: database security. In
src/app.controller.ts
we haveLoginGuard
on login route that after some hops takes us toauth.service.ts
. There we pass username and password:Let's say we pull the user from the database so we certainly want to have
username
validated first. But Guards are executed before Pipes so LoginGuard will run before ValidationPipe could return "400 Bad request" on some malicious payload.So, how to make LoginGuard use ValidationPipe to check the input before proceeding with using it for its auth job?
Same opinion as you.
Should login logic with passport be implemented in Service instead of Guard?
process order: ValidationPipe -> Controller@Post -> LoginService -> DB
dev.to/umasankarswain/how-to-updat...
Hey John, thanks for the article. Not much documentation is available for sessions using NestJS so this is article is pretty helpful. That said I did waste a little bit of time because executing
app.use(passport.initialize())
would crash using your code sample. After some struggling, I figured out passport is imported incorrectly in your sample code. When importing passport inmain.ts
, the import should beimport passport from 'passport';
insteadimport * as passport from 'passport';
. If you import using the later statement, theinitialize
function is undefined. You may want to correct this to avoid headaches to developers using code samples from your article to get sessions to work with NestJS :)Cheers
I had the same problem using
import * as passport from 'passport';
But if replace it with
import passport from 'passport';
, my app doesn't even boots. It says:node:25616) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'initialize' of undefined
at bootstrap (/home/lamps/dev/mvc-sessions/dist/main.js:21:32)
(Use
node --trace-warnings ...
to show where the warning was created)(node:25616) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag
--unhandled-rejections=strict
(see nodejs.org/api/cli.html#cli_unhand...). (rejection id: 1)(node:25616) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
dev.to/umasankarswain/how-to-updat...
Hi!
I tried
import passport = require('passport');
and it seems to work. I'll keep this way for now. Does anyone knows the correct import syntax ?
dev.to/umasankarswain/how-to-updat...
Thank you so much for the detailed article. I have a couple of questions now though:
Why isn't this simply in the official documentation? Feels a bit strange as I went with the official website's documentation to set up (a working) JWT interface and now I read this and I'm super confused to which I should follow, as there are different implementation(s) for the LocalStrategy here.
Are there any plans to implement a simple(r) session related documentation to the official website?
Thank you once again to you and the rest of the team for the framework and time of this write-up.
I'm in the same situation right now. I followed the documentation, built the JWT auth system, knowing nothing about authorization, but having heard JWT used everywhere. Started reading about authorization, sessions, realized that stateless authorization isn't applicable to my use case at all. I wish there was more information on stateful authorization with Nest.js.
I suggest you to read the blog post and linked, and its follow-up.
@joaquimley and @rafaelsofizadeh The JWT implementation from the nest documentation is actually more of an example of how to authenticate using JSON Web Tokens as opposed to sessions. There's been a lot of debate over the years as to whether JWT is appropriate, let alone secure for Single Page Apps. To cut through the chase, if you're building a traditional site (a web app with multiple pages which cause the browser to refresh when navigating) or a Single Page App, just stick to using Sessions. If you're building a public REST API or a mobile app with a backend service, then JWT might be more useful, and even then, according to some experts, it's better to have one app handle authentication only while keeping other apps separate.
I'm assuming you're both building traditional or single-page apps, so in your case, the documentation doesn't explicitly tell you how to set up authentication along with sessions. Here's what I recommend: follow the docs on Authentication all the way down until you finish setting up your Local Guard based on AuthGuard from @nestjs/passport. The next section is JWT, so ignore all of that. Instead, follow the instructions on how to set up sessions on express, so you will need this article. This means attaching and configuring session and passport on the bootstrap function, then setting up your serializer, like the article mentions, and finding a session Store to replace the development store that express-session comes with. In my case, I'm building a custom one that implements the Store interface but you may want to look for one in the express-session docs. Hope this helps!
I would like to post a minor correction/suggestion. If this is written for a REST API,
request.logout()
will only remove the user from the session, but the session itself won't be removed from the session store. Instead, in the logout route you should write something like this:where ExpressResponse is the Response type from express, so as not to clash with Response type from @nestjs/common
request.session.destroy()
will remove the session from the store, and on the callback, the session cookie must be deleted since neither Nest nor Passport seem to do this for you.this.config.get("SESSION_NAME")
will retrieve the cookie name from a .env file, assuming you set up @nestjs/config library; otherwise just type in the name of the session cookie which by default isconnect.sid
. Lastly,response.end()
will finish the request manually since it the response object was injected.EDIT: the previous
response.clearCookie()
call will not work if you had set httpOnly to true, so you must specify the whole cookie's parameters as shown above. Apparently all the previous parameters have to match except max age and expires.Thanks for an awesome tutorial!
One note for anyone who encounters the same issue I did for the logout functionality.
I receieved the following error log when implementing per the article:
Error: req#logout requires a callback function
Passing the
res.redirect('/)
as a callback to thereq.logout
method call fixed this.Thank you @johnbiundo it's a great article. By the way, can you continue this project with mongoose instead of hard-coded memory?
Thanks for the feedback @Deary. Yes, at some point I would like to provide a fuller example, including a User store, but at the moment I'm focused a little bit more on the aspects of the solution that are relatively "unique" to NestJS.
I'd love some elaboration on that serialize/deserialize part. How the data is stored between requests? How to plug my solution (some custom memory store, some database etc.) into this framework?
Excellent article, John! It's very carefully written and covers a lot of stuff. I have a question about the input Passport's local strategy accepts. It seems the JSON from a user has to be with keys "username" and "password". Is there a way to accept an "email" field instead of a "username" field?
Thanks a lot,
I tried to make authentication with JWT but I cannot perform logout,
I want to be able to actually control the token, delete it, upgrade it if the user used it in the expiration time again,
here's a stackoverflow question I have posted
stackoverflow.com/questions/595473...
Hey John, awesome article! I hope you keep them coming! I struggle specifically with setting a default strategy with passport? I tried setting it in the module import via "PassportModule.register({ defaultStrategy: 'jwt' })," in both, once the AppModule and once my AuthModule, but it doesn't seem to work?
When setting the guard via decorator it works no problem? Hope you can point me in the right direction, cheers!
Hi Felix, thanks for the feedback!
So, have you looked at the code sample here: docs.nestjs.com/techniques/authent... and does your code follow that pattern? You should only need to do this in the AuthModule if this is where you are registering Passport. If so, and this still isn't working, and you have a public repo, I'd be happy to take a look. Good luck!
Thank you! Thank you! Thank you! @johnbiundo
This is perhaps the first tutorial on NestJS that has a login flow appropriate to bootstrap an application with view components.
All the code presented is clear, well documented, and works out of the box!
Would love to see more of your content.
- vlad
Excellent write-up John!! 👏👏
Thanks Mark! 😃
Hey! Awesome ressource, thank you so much.
Can i continue this article with the implementation of mongo-connect ?
Great post @johnbiundo thank you for sharing your knowledge with us.
Hope you get deeper details into authentication with NestJs.
Thanks for the feedback @ruslangonzalez ! I do plan to in the near future.
Thanks for filling a much needed niche, this is exactly what I was looking for!
Thanks Christian, This article very useful. I had problem with “request.flash('loginError', 'Please try again!'); ” I cannot call flash method in request , Does anyone has same problem?
I experienced a similar issue. In my case I was getting the following error log:
I realized I'd neglected to install the corresponding types package for
connect-flash
(@types/connect-flash
) which resolved the issue for me.Thanks for this. Lately, I have been struggling to get this to work with OpenID connect hey, have you done it before? would really appreciate your help.
This article is very helpful to me, thank you @johnbiundo .
But I have a question that the user info is not the must-have for some routes, so how can I implement this?
This is one of the best and helpful tutorials I have read on NestJS. I have comeback to this post a lot of times reading up on it from time to time.
Thank you John
Great job!
Could you update your solution to implement redirection from login page to a profile page when user is already logged-in?
I tried doing something like this and it works, but I end up with error:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Any ideas? Couldn't resolve it with solutions from many Stack Overflow topics.
Great article! Simple written, everything clear. Thanks John!
Thank you very much! You helped me a lot!
Thanks for such a great tutorial! This might be not very new but still completely available.
It's a missing part of the official docs!
Excellent article, I am currently implementing authentication with saml passport-saml, I have been looking for the solution for a few days. I'm going to apply the techniques you mention.