Building a Login System in Node.
js and MongoDB
June 4, 2012 Javascript | [Link] 62 Comments
SEARCH
This past week I finally got around to playing with [Link] and am really impressed with how simple it was to get a server and database up and running in literally minutes. Once there, I thought a good first project to explore the platform would be to try building a simple login system analogous to what I feel like Ive built a million times in mysql & php. So after thinking about it a bit, I knew these were the basic features I wanted to implement :
Categories
Actionscript / Flash General News [Link] Processing Arduino Javascript OpenFrameworks Python Travel
Login Panel
Just a simple login panel with the ability to reset a lost password and of course the ability to create an account for first time users. An option to remember me that saves the users data in a local cookie allowing them to bypass the login screen whenever they revisit the site.
Raspberry PI Unix
Recent Twitter
31 March 2013 at 10:45pm
Follow @braitsch
373 followers
@sansumbrella will do, cheers mate!
@sansumbrella gotcha, thanks dude. really appreciate the nod. i was really scratching my head over this.
31 March 2013 at 10:43pm
@sansumbrella ah thanks! question tho would that require every triangle to have unique vertices? even if they're in the same position?
31 March 2013 at 10:40pm
Recent Posts
Controlling 24 LEDs with [Link] & a Raspberry PI How to Setup [Link] on a Raspberry PI Why Isnt Stylus Compiling my CSS? Internet Service Provider Health Monitor Building a [Link] Chat Application and Sharing [Link] Across Multiple Subdomains
New Account Screen
Asimple form that allows a new user to set their username & password, as well as some personal data such as their real name, email and location.
Popular Posts
converted by [Link]
Transform Tool - Drag, Scale and Rotate in Flash at Runtime 66 comments Building a Login System in [Link] and MongoDB 62 comments Dynamically Create an Image in Flash and Save it to the Desktop or Server 56 comments
And Some Recent Snaps on Flickr...
Account Update Screen
Almost identical to the account creation screen, with the slight modification that the username field is deactivated so it cannot be changed allowing us to preserve a unique key to identify each account. Here well also add a button that will allow users to delete their account.
Password Retrieval
Asimple modal window where users can request an email to reset their password.
converted by [Link]
If youd like to jump ahead : check out the full working version of the app or download and install the source code here
Standing on the Shoulders of Giants
One of the most impressive highlights of the [Link] ecosystem in my opinion is the incredible myriad of libraries actively being produced to take much of the heavy lifting out of building your app. In our login system well leverage the following libraries to get us up and running : [Link] [Link] framework with a ton of convenient features that make working in Node much faster MongoDb ANoSQL database well use to save our account data Jade Atemplating engine that allows us to write less verbose HTML Stylus ACSS-preprocessor with a zillion amazing features that greatly take the pain out of writing traditional CSS [Link] Middleware to easily dispatch emails from our [Link] server [Link] Alightweight library for convenient date parsing & formatting And last but not least the inimitableTwitter Bootstrap UI library to layout our forms and pages with beauty and consistency across browsers.
Application Structure
Our login system will of course need to execute code in two environments, on the client machine and on the server. On the client side well need to display our HTML pages, handle user interactions, and validate the various forms our app uses before sending their data to the server. On the server side well layout our HTML pages using Jade templates and create a few custom modules to read and write to the database and dispatch emails for password retrieval. The general layout of these two environments is as follows : Server-Side Components : views jade templates that compile to HTML [Link] [Link] [Link] modules helper classes that interact with the database and dispatch emails [Link] [Link] Client-Side Components : views these setup our form controllers & modal windows [Link] [Link] [Link] controllers handle user interactions [Link] [Link] [Link]
converted by [Link]
form-validators validate forms and display errors [Link] [Link] [Link] [Link] Note : Because the new account and update account forms are so similar, Ive consolidated the code that validates them into one file called AccountValidator and then put any code that differs between them in their respective controllers SignupController & HomeController.
So How Does All This Actually Work?
The basic page flow can be generalized into two parts: Part 1 : Getting the Page 1. Auser arrives at [Link] and requests the root page or / 2. [Link] on our server sees this GET request and returns [Link], the view associated with [Link] However before it does this, it checks the GET request object for a username & password cookie and if they exist and validate, redirects the browser to [Link]
var AM = require('./modules/account-manager'); [Link]('/', function(req, res){ // check if the user's credentials are saved in a cookie // if ([Link] == undefined || [Link] == undefined){
[Link]('login', { locals: { title: 'Hello - Please Login To Your Account' } } ); } else{
// attempt automatic login //
[Link]([Link], [Link], function(o){ if (o != null){ [Link] = o; [Link]('/home'); } else{ [Link]('login', { locals: { title: 'Hello - Please Login To Your Account' } } ); } }); } }); 3. Otherwise, the server renders [Link] into the HTML login form and sends it to the browser. 4. Once the HTML is received by the client, the script tags in the page request the JavaScript files associated with the login page, namely : /js/views/[Link] /js/controllers/[Link] /js/form-validators/[Link] /js/form-validators/[Link] 5. These four component files setup the form and alert windows, listen for user interaction and validate the form before sending it back to the server. Part 2 : Posting the Page 1. Auser enters their username & password and hits submit 2. [Link] validates the form and then allows [Link] to send its contents to the server as a POST request. 3. [Link] on the server sees the incoming POST request and forwards the username & password to the AccountManager module which compares what the user entered to the values stored in the database. Once [Link] gets a response from the AccountManager it either sends a 200 (pass) or 400 (fail) status code back to the browser.
var AM = require('./modules/account-manager'); var EM = require('./modules/email-dispatcher'); [Link]('/', function(req, res){ if ([Link]('email') != null){ [Link]([Link]('email'), function(o){ if (o){
[Link]('ok', 200); [Link](o, function(e, m){ [Link]('error : '+e, 'msg : '+m)}); } else{
converted by [Link]
[Link]('email-not-found', 400); } }); } else{
// attempt manual login //
[Link]([Link]('user'), [Link]('pass'), function(e, o){ if (!o){ [Link](e, 400); }else{ [Link] = o; if ([Link]('remember-me') == 'true'){ [Link]('user', [Link], { maxAge: 900000 }); [Link]('pass', [Link], { maxAge: 900000 }); } [Link](o, 200); } }); } }); 4. [Link] which owns the login form, hears the returned value and either redirects the user to the logged in page, or shows an alert window that displays a specific error message.
var lv = new LoginValidator(); var lc = new LoginController(); // main login form //
$('#login-form').ajaxForm({ beforeSubmit : function(formData, jqForm, options){ if ([Link]() == false){ return false; } else{
// append 'remember-me' option to formData to write local cookie //
[Link]({name:'remember-me', value:$("input:checkbox:checked").length == 1}) return true; } }, success : function(responseText, status, xhr, $form){ if (status == 'success') [Link] = '/home'; }, error : function(e){ [Link]('Login Failure', 'Please check your username and/or password'); } });
This communication sequence between the server and the client is essentially what is happening on each page of our app. In Summary 1. The user arrives at a page 2. [Link] returns the appropriate Jade template that renders the pages HTML and loads its JavaScript controllers 3. The user interacts with the page typically by filling out and submitting a form 4. Some JavaScript validates the form and sends its data back to the server 5. [Link] forwards the data to the AccountManager for comparison, entry, deletion, etc. in the database 6. The AccountManger returns a pass or fail response back to [Link] which then gets sent back to the client 7. JavaScript on the client handles the response by either redirecting the browser or showing a modal window with a detailed response. As you can see the communication between the client and server is not terribly complicated however it does beg the question as to how to best organize this communication into components and modules. So with that in mind, the source for this app is fully available on github with instructions on how to install and get this running on your local machine. As always feedback, questions and suggestions for improvement are most welcome.
ALSO ON THE CHOREOGRAPHY OF COLOR AND CODE AROUND THE WEB
How to Drain Liquid From Behind the Ear Drum What Food To Avoid If You Have Acid Reflux VIDEO: Path To The Pros 2013: Montee Ball Are You Forgetting
converted by [Link]
Consumer Car Reviews
61 comments
Leave a message...
Best Community
Andrew Eremenko
2 months ago
Thank you for this great app. But I have some questions. Why did you store login and password in cookies? It's not secure, isn't it? How about idea to make auth token (or whatever) like at twitter or facebook?
18
Reply
Share
Donald Trap
5
5 months ago
figured it out. had to start mongodb before running node app
Reply
Share
bren101
3 months ago
Two small suggestions: 1. Upgrade to bcrypt for more robust salt & hash quality, and less lines of code as a bonus. 2. Write the time/date to mongodb as a native Date() object, so that it translates into a native mongodb ISODate structure.
2
Reply
Share
Declan E.
5 months ago
Hi, Sorry to post again but I have one more question. I see you have used Bootstrap, and for anyone new to using node/jade I'm finding it quite difficult to apply the logic and workings of your project to a simple login system I'm trying to make. My system is a simple html page, with CSS dictating where the login link is, and the jquery/javascript file is a simple lightbox type idea. But I'm lost applying this to your project! How would I go about re-creating something similar without bootstrap, it's rather confusing for a newbie! Thanks again, Declan
3 1
Reply
Share
hugozap
1
3 months ago
Why is [Link]([Link]([Link] + '/app/server')); required? Doesn't it expose the server folder contents?
Reply
Share
braitsch Mod
hugozap 3 months ago
You're right that does and was a security vulnerability. It was there to allow access to vendor libs that were in /server/vendor. Those files have since been moved to /public/vendor as of v1.2.1
0
Reply
Share
Mulyana
6 months ago
Stephen, do you have any hints to get these login systems to work under Express 3.x? Thanks for nice tutorial :)
1
Reply
Share
braitsch Mod
0
Mulyana 3 months ago
Updated to [Link] v3.0.6 as of v1.3.0
Reply Share
Bryan Nichols
7 months ago
Stephen, Another question for you. Can you explain what you are doing with this call: require('./app/config')(app, exp)? It looks like you are passing app and exp to the require call but after looking at the node API I am at a loss.
converted by [Link]
I just want to say that not only is this an awesome project, I am really floored by the exceptional organization of it all. I am trying to build my first Node app and this gives me something to strive for. I wanted to better understand how you segregated everything because it makes the project so much more organized. Do you have any recommendations for learning Node or JS in general? I've got a few books on it, but i am finding that even the ones published last month have out of date source code due to the momentum of Node. Thanks so much!
1
Reply
Share
Stephen Braitsch
9 months ago
Hi Tara, thanks for asking. Feel free to use the code in any way you like. If you wind up using it in a public facing project, it'd be great if you posted a link here so we can check it out. Otherwise I've imposed no restrictions on how you can use this code. Enjoy.
1
Reply
Share
John F Dutcher
a month ago
It's such a nice sample. But oddly..if I install mongodb with npm...a mongodb folder is created in node_modules that has no bin folder and no [Link] or [Link] with which to start the server. If I replace the mongodb folder in node_modules with an empty one and unzip the windows download from mongodb web site into it...all needed exe's are there and I can start the server db and the shell. the 'sever' folder of the app fail when trying to 'require' mongodb ( require ('mongodb').db
0
Reply
Share
Alex
2 months ago
Thanks for this practical example. I was testing the app out on localhost and tried a password rest. I could not reset my password successfully with the message "I'm sorry something went wrong, please try again." Assuming i have configured my smtp server setting correctly, what could be wrong here? On the node [Link] screen: TypeError: Cannot read property 'email' of undefined ..blah blah I noticed your website did not have the smtp notification setup too. Many thanks in advance. :)
0
Reply
Share
Etna Mianuloe
2 months ago
Thanks for tutorial!! Trying to figure it out.. Hard as I am a beginner. In Part 2 point 2 [Link] validates the form and then allows [Link] to send its contents to the server as a POST request. What's the code for it in [Link]?
0
Reply
Share
Mark Barton
2 months ago
Hi, Great example - thanks. One thing - on the updatePassword method in the [Link] file, I couldnt get it to return a HTTP 200 unless I amended the callback which was within the [Link] call i.e. Originally it was this: [Link](o, {safe: false}, callback); I added the account object so something was returned back to the callng method. [Link](o, {safe: false}, callback(o)); I am new to node so I wasnt sure if this was correct - else I would have done the update via GIT. I am going to have a go at using mongoose as a learning exercise - do you foresee any issues? Thanks Mark
0
Reply
Share
Eric Fleischmann
0
2 months ago
This is righteous. Thanks for sharing. Will try to get it to work with mongoose and bcrypt for my application.
Reply
Share
tylerh
0
3 months ago
This is sweet thanks for posting this!
Reply
Share
converted by [Link]
bren101
0
3 months ago
For security, shouldn't the validation code really be running on the server, not the client?
Reply
Share
braitsch Mod
0
bren101 3 months ago
Authentication is happening on the server, what are you talking about?
Reply Share
bren101
braitsch 3 months ago
I'm talking about all the code in form-validators. Apologies if I'm reading it wrong, but if a malicious user bypasses the client-side validation, doesn't it mean the server might do things such as write invalid email addresses into its database?
0
Reply
Share
braitsch Mod
bren101 3 months ago
Ah yes I see what you're talking about. Sure the client side validation just attempts to protect against common user errors such as an invalid email or empty form field. If you wanted to protect against something say like a SQL injection you'd want to add that sanitization in the AccountManager before allowing a write to the DB.
0
Reply
Share
flo
0
3 months ago
Tank's for sharing such great dev. Can somebody tell ma what [Link] and [Link] use for ?
Reply
Share
Jube
3 months ago
Hello Braitsch, Great tutorial. As a beginner I am not sure how did you host it in [Link] --Jube
0
Reply
Share
WaltDjr
3 months ago
Hi Stephen, I'm fairly new to node and everything is working great except the "Forgot your Password." error : code 5 error : previous { [Error: getaddrinfo ENOENT] code: 'ENOTFOUND', errno: 'ENOTFOUND', syscall: 'getaddrinfo' } error : smtp undefined I have changed the [Link] to point to my smtp server with my credentials. I've searched on this error and I'm not really finding anything. Can you point me in the right direction on where to start troubleshooting this? Thanks in advance and thanks for this example. It will definitely help get my feet wet in Node and Mongo along with the other modules you have used. WaltDjr
0
Reply
Share
Tim Coombs
0
4 months ago
Great use of nodejs and jade. I hadn't heard of jade, but now after a couple days of developing i can't not use it!
Reply
Share
Mark Coles
4 months ago
Hi Stephen I like the example, very clear and easy to follow, I am in the process of creating a new site with a user account aspect but will be using you are not using it, how easy would it be to update/ edit it to have it work with [Link]? Thank you for you advice.
0
Reply
Share
Stephen Braitsch
Mark Coles 4 months ago
@Mark Coles [Link] is a very easy to work with. Here's another project I wrote that shows how to setup a simple chat application using it.
0
Reply
Share
JOhn terry
5 months ago
converted by [Link]
Never mind, that was it!
0
Reply
Share
JOhn terry
0
5 months ago
Hey Donald, how did u start the monogodb? Did it not install as a dependency? I tried to start it with mongod
Reply
Share
Declan E.
5 months ago
Stephen, Great program. I have the program running on localhost:8080 to test on my home computer, I have registered an account an then tested it by logging in with it. Where do I now go to actually see the databases created by the mongodb connection? So that I can get a clearer idea of what your program is storing and where. Another question I have, when hosting this on the internet as you have done with your example for us to see, how do you go about this, for example on my home computer, I load cmd prompt...run mongo...then go to the login app's folder and run this...and connect in my browser using localhost:8080...How would you apply this to a real website? I ask this because of course on my computer at home I have mongo installed, nodejs installed, and all the other features you need for other extensions such as npm, bcrypt etc. Thanks, Declan
0
Reply
Share
WeLeven
5 months ago
Hi, just want to know is there an easy way to prevent the same user from logging in from different machines (same IP but different ports, or different IP altogether)? I tried to add state to each account of the user to tracked if they are logged in or out but it will fail if they close the browser without logging out first.
0
Reply
Share
Donald Trap
5 months ago
Thanks, I finally got it installed on Windows XP. However, now i'm experiencing an error within a few seconds of starting node app. Error: failed to connect to [localhost:27017]
0
Reply
Share
Donald Trap
5 months ago
Hi I'm currently having issues with the install. I followed all the requirements/dependencies but still get errors when I run 'npm install -d' below is copied from my npm-debug 189 info postuninstall [email protected] 190 error [email protected] install: `node-gyp rebuild` 190 error `cmd "/c" "node-gyp rebuild"` failed with 1 191 error Failed at the [email protected] install script. 191 error This is most likely a problem with the bcrypt package, 191 error not with npm itself. 191 error Tell the author that this fails on your system: 191 error node-gyp rebuild 191 error You can get their info via: 191 error npm owner ls bcrypt 191 error There is likely additional logging output above. 192 error System Windows_NT 5.1.2600 193 error command "C:\\Program Files\\nodejs\\\\[Link]" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\[Link]" "install" "-d" 194 error cwd C:\Documents and Settings\Administrator\My Documents\GitHub\node-login 195 error node -v v0.8.14 196 error npm -v 1.1.65 197 error code ELIFECYCLE 198 verbose exit [ 1, true ]
0
Reply
Share
Stephen Braitsch
Donald Trap 5 months ago
I had an error once attempting to download bcrypt due to one of the servers hosting it being offline. suggestions, or try installing it again in a few hours.
0
Reply
Share
converted by [Link]
Donald
0
5 months ago
Would it be difficult to implement a captcha/recaptcha system to prevent spam?
Reply
Share
Andrei Soare
0
5 months ago
Thanks, Stephen! Great intro to [Link] for us beginners ;)
Reply
Share
Ali Hassan
6 months ago
Also, once I have unchecked the "remember me" checkbox and then I logout and return back to the login screen here still the "remember me" checkbox appears checked?
0
Reply
Share
Ali Hassan
6 months ago
Is it should be the desired behavior? It should be in such way that when I have unchecked "remember me" checkbox and then I quit the browser, then It should ask be to login again as its session has expired? Please correct me.
0
Reply
Share
Ali Hassan
6 months ago
Hi STEPHEN, That is AWESOME!!!! I am making an website using the same technology that you have used, so It is really really helpful for me. BUT:( One thing in which I am stuck is why the "Remember me" check is not working as desired:( I unchecked the "Remember Me" check and then quit my Mozilla Firefox but when I reopen your home screen " redirected me to the home page whereas, I was expecting that It will redirect me to the login screen to login again but It did not:(
0
Reply
Share
Stephen Braitsch
0
Ali Hassan 6 months ago Share
You have to manually logout for the "remember me" option to stop taking effect.
Reply
Mihai
6 months ago
Could i just ask why i should use my own (copying yours :P) login model instead of using something like passport? just want to know what advantages/disadvantages that might mean since im just starting with [Link]
0
Reply
Share
Stephen Braitsch
Mihai 6 months ago
@mihai Use whatever works for your project, although understanding how I approached this problem may help you learn something. @mulyana I unfortunately have not had the time to port this to Express 3. If you want to fork it and submit a pull request that would be fantastic.
0
Reply
Share
Florent Wozniak
Stephen Braitsch 3 months ago
Hi Stephen, I'm new to Node and I'd like to ask you what are the modifications that need to be done to port your code to Express 3 ? I struggle for the last two day with it wo success :-( I've made lots of search in google and also asked in Stakeoverflow forum but with no response. Express and firebug return to me no error. It is very frustrating because your code works nicely with Express 2. Thank you for your reply (even a clue would be great). Flo
0
Reply
Share
braitsch Mod
Florent Wozniak 3 months ago
It shouldn't require much to migrate the app to Express3, it's on my to do list but I haven't had the time. If you are able to successfully migrate the project, go ahead and issue a pull request.
0
Reply
Share
braitsch Mod
braitsch 3 months ago
converted by [Link]
I just updated the app to [Link] v3.0.6 as of v1.3.0.
1
Reply
Share
Florent Wozniak
braitsch 3 months ago
Many thinks Braitsch i really appreciate. I guess you now use 'extends' instead of layout in .jade file (got it) :) did you make other changes ?
0
Reply
Share
daslicht
6 months ago
That you for this wonderful example. In you example you store the username and the password in the cookie. How about using a Session to remember a user ? e.g.: [Link] In that case only a session ID would be stored in the cookie. Woundnt this be more secure? Or is that session ID some easy to fake? generate ? What do you think ?
0
Reply
Share
Bryan Nichols
7 months ago
Stephen, I think I figured it out. require is returning a function and you are calling that function immediately and passing in app an exp. Very clever way to structure code. I am going to try and fork your repo to see if i can get it to work with mysql. If anything, it's awesome to look through your code base; I want to aspire to aspire to this level of coding. Thanks again for writing this tutorial, I really appreciate it.
0
Reply
Share
Stephen Braitsch
0
Bryan Nichols 7 months ago Share
Thanks Bryan for the feedback, glad to hear you found this useful. Cheers!
Reply
Jake
7 months ago
Stephen - Great tutorial and thanks for sharing. I'm just beginning to learn javascript and node and am a bit unclear on the use variables 'o','e',and 'd' inside the anonymous functions called from account-manager and [Link]. Can you help me better understand where these variables are first instantiated, assigned, and how they function within the program? Appreciative of any additional information you can provide.
0
Reply
Share
Stephen Braitsch
Jake 7 months ago
Hi, those are just the incoming arguments of the function. They are mapped to whatever values you pass to the function when you call it. HTH
0
Reply
Share
Load more comments
Comment feed
Subscribe via email
converted by [Link]
converted by [Link]
converted by [Link]