├── config
├── database.js
└── passport.js
├── package.json
├── .gitattributes
├── scripts
└── create_database.js
├── README.md
├── views
├── index.ejs
├── profile.ejs
├── signup.ejs
└── login.ejs
├── server.js
├── app
└── routes.js
└── .gitignore
/config/database.js:
--------------------------------------------------------------------------------
1 | // config/database.js
2 | module.exports = {
3 | 'connection': {
4 | 'host': 'localhost',
5 | 'user': 'root',
6 | 'password': 'password'
7 | },
8 | 'database': 'my_schema',
9 | 'users_table': 'users'
10 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-authentication",
3 | "main": "server.js",
4 | "scripts": {
5 | "start": "node ./server"
6 | },
7 | "dependencies": {
8 | "bcrypt-nodejs": "0.0.3",
9 | "body-parser": "^1.13.1",
10 | "connect-flash": "^0.1.1",
11 | "cookie-parser": "^1.3.5",
12 | "ejs": "^2.3.2",
13 | "express": "^4.13.0",
14 | "express-session": "^1.11.3",
15 | "morgan": "^1.6.0",
16 | "mysql": "^2.7.0",
17 | "passport": "^0.2.2",
18 | "passport-local": "^1.0.0"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 | *.sln merge=union
7 | *.csproj merge=union
8 | *.vbproj merge=union
9 | *.fsproj merge=union
10 | *.dbproj merge=union
11 |
12 | # Standard to msysgit
13 | *.doc diff=astextplain
14 | *.DOC diff=astextplain
15 | *.docx diff=astextplain
16 | *.DOCX diff=astextplain
17 | *.dot diff=astextplain
18 | *.DOT diff=astextplain
19 | *.pdf diff=astextplain
20 | *.PDF diff=astextplain
21 | *.rtf diff=astextplain
22 | *.RTF diff=astextplain
23 |
--------------------------------------------------------------------------------
/scripts/create_database.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Created by barrett on 8/28/14.
3 | */
4 |
5 | var mysql = require('mysql');
6 | var dbconfig = require('../config/database');
7 |
8 | var connection = mysql.createConnection(dbconfig.connection);
9 |
10 | connection.query('CREATE DATABASE ' + dbconfig.database);
11 |
12 | connection.query('\
13 | CREATE TABLE `' + dbconfig.database + '`.`' + dbconfig.users_table + '` ( \
14 | `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, \
15 | `username` VARCHAR(20) NOT NULL, \
16 | `password` CHAR(60) NOT NULL, \
17 | PRIMARY KEY (`id`), \
18 | UNIQUE INDEX `id_UNIQUE` (`id` ASC), \
19 | UNIQUE INDEX `username_UNIQUE` (`username` ASC) \
20 | )');
21 |
22 | console.log('Success: Database Created!')
23 |
24 | connection.end();
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Complete Guide to Node Authentication with MySQL
2 |
3 | ❤️ Visit [FullStack Framework 2023](https://github.com/manjeshpv/awesome-sandbox)
4 |
5 | Code for the entire scotch.io tutorial series: Complete Guide to Node Authentication with MongoDB
6 |
7 | Current version database is ported to MySQL
8 |
9 | We will be using Passport to authenticate users locally,
10 |
11 | ## Instructions
12 |
13 | If you would like to download the code and try it for yourself:
14 |
15 | 1. Clone the repo: `git clone git@github.com:manjeshpv/node-express-passport-mysql.git`
16 | 1. Install packages: `npm install`
17 | 1. Edit the database configuration: `config/database.js`
18 | 1. Create the database schema: `node scripts/create_database.js`
19 | 1. Launch: `node server.js`
20 | 1. Visit in your browser at: `http://localhost:8080`
21 |
22 |
23 | Licence: 1
24 |
--------------------------------------------------------------------------------
/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Node Authentication
6 |
7 |
8 |
11 |
12 |
13 |
23 |
24 |
--------------------------------------------------------------------------------
/views/profile.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Node Authentication
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
Local
26 |
27 |
28 | id: <%= user.id %>
29 | username: <%= user.username %>
30 | password: <%= user.password %>
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/views/signup.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Node Authentication
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
Signup
18 |
19 |
20 | <% if (message.length > 0) { %>
21 |
<%= message %>
22 | <% } %>
23 |
24 |
25 |
37 |
38 |
39 |
40 |
Already have an account? Login
41 |
Or go home.
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | // server.js
2 |
3 | // set up ======================================================================
4 | // get all the tools we need
5 | var express = require('express');
6 | var session = require('express-session');
7 | var cookieParser = require('cookie-parser');
8 | var bodyParser = require('body-parser');
9 | var morgan = require('morgan');
10 | var app = express();
11 | var port = process.env.PORT || 8080;
12 |
13 | var passport = require('passport');
14 | var flash = require('connect-flash');
15 |
16 | // configuration ===============================================================
17 | // connect to our database
18 |
19 | require('./config/passport')(passport); // pass passport for configuration
20 |
21 |
22 |
23 | // set up our express application
24 | app.use(morgan('dev')); // log every request to the console
25 | app.use(cookieParser()); // read cookies (needed for auth)
26 | app.use(bodyParser.urlencoded({
27 | extended: true
28 | }));
29 | app.use(bodyParser.json());
30 |
31 | app.set('view engine', 'ejs'); // set up ejs for templating
32 |
33 | // required for passport
34 | app.use(session({
35 | secret: 'vidyapathaisalwaysrunning',
36 | resave: true,
37 | saveUninitialized: true
38 | } )); // session secret
39 | app.use(passport.initialize());
40 | app.use(passport.session()); // persistent login sessions
41 | app.use(flash()); // use connect-flash for flash messages stored in session
42 |
43 |
44 | // routes ======================================================================
45 | require('./app/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport
46 |
47 | // launch ======================================================================
48 | app.listen(port);
49 | console.log('The magic happens on port ' + port);
50 |
--------------------------------------------------------------------------------
/views/login.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Node Authentication
6 |
7 |
8 |
11 |
12 |
13 |
14 |
15 |
Login
16 |
17 |
18 | <% if (message.length > 0) { %>
19 |
<%= message %>
20 | <% } %>
21 |
22 |
23 |
39 |
40 |
41 |
42 |
Need an account? Signup
43 |
Or go home.
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/routes.js:
--------------------------------------------------------------------------------
1 | // app/routes.js
2 | module.exports = function(app, passport) {
3 |
4 | // =====================================
5 | // HOME PAGE (with login links) ========
6 | // =====================================
7 | app.get('/', function(req, res) {
8 | res.render('index.ejs'); // load the index.ejs file
9 | });
10 |
11 | // =====================================
12 | // LOGIN ===============================
13 | // =====================================
14 | // show the login form
15 | app.get('/login', function(req, res) {
16 |
17 | // render the page and pass in any flash data if it exists
18 | res.render('login.ejs', { message: req.flash('loginMessage') });
19 | });
20 |
21 | // process the login form
22 | app.post('/login', passport.authenticate('local-login', {
23 | successRedirect : '/profile', // redirect to the secure profile section
24 | failureRedirect : '/login', // redirect back to the signup page if there is an error
25 | failureFlash : true // allow flash messages
26 | }),
27 | function(req, res) {
28 | console.log("hello");
29 |
30 | if (req.body.remember) {
31 | req.session.cookie.maxAge = 1000 * 60 * 3;
32 | } else {
33 | req.session.cookie.expires = false;
34 | }
35 | res.redirect('/');
36 | });
37 |
38 | // =====================================
39 | // SIGNUP ==============================
40 | // =====================================
41 | // show the signup form
42 | app.get('/signup', function(req, res) {
43 | // render the page and pass in any flash data if it exists
44 | res.render('signup.ejs', { message: req.flash('signupMessage') });
45 | });
46 |
47 | // process the signup form
48 | app.post('/signup', passport.authenticate('local-signup', {
49 | successRedirect : '/profile', // redirect to the secure profile section
50 | failureRedirect : '/signup', // redirect back to the signup page if there is an error
51 | failureFlash : true // allow flash messages
52 | }));
53 |
54 | // =====================================
55 | // PROFILE SECTION =========================
56 | // =====================================
57 | // we will want this protected so you have to be logged in to visit
58 | // we will use route middleware to verify this (the isLoggedIn function)
59 | app.get('/profile', isLoggedIn, function(req, res) {
60 | res.render('profile.ejs', {
61 | user : req.user // get the user out of session and pass to template
62 | });
63 | });
64 |
65 | // =====================================
66 | // LOGOUT ==============================
67 | // =====================================
68 | app.get('/logout', function(req, res) {
69 | req.logout();
70 | res.redirect('/');
71 | });
72 | };
73 |
74 | // route middleware to make sure
75 | function isLoggedIn(req, res, next) {
76 |
77 | // if user is authenticated in the session, carry on
78 | if (req.isAuthenticated())
79 | return next();
80 |
81 | // if they aren't redirect them to the home page
82 | res.redirect('/');
83 | }
84 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #################
2 | ## Eclipse
3 | #################
4 |
5 | *.pydevproject
6 | .project
7 | .metadata
8 | bin/
9 | tmp/
10 | *.tmp
11 | *.bak
12 | *.swp
13 | *~.nib
14 | local.properties
15 | .classpath
16 | .settings/
17 | .loadpath
18 |
19 | # External tool builders
20 | .externalToolBuilders/
21 |
22 | # Locally stored "Eclipse launch configurations"
23 | *.launch
24 |
25 | # CDT-specific
26 | .cproject
27 |
28 | # PDT-specific
29 | .buildpath
30 |
31 |
32 | #################
33 | ## Visual Studio
34 | #################
35 |
36 | ## Ignore Visual Studio temporary files, build results, and
37 | ## files generated by popular Visual Studio add-ons.
38 |
39 | # User-specific files
40 | *.suo
41 | *.user
42 | *.sln.docstates
43 |
44 | # Build results
45 |
46 | [Dd]ebug/
47 | [Rr]elease/
48 | x64/
49 | build/
50 | [Bb]in/
51 | [Oo]bj/
52 |
53 | # MSTest test Results
54 | [Tt]est[Rr]esult*/
55 | [Bb]uild[Ll]og.*
56 |
57 | *_i.c
58 | *_p.c
59 | *.ilk
60 | *.meta
61 | *.obj
62 | *.pch
63 | *.pdb
64 | *.pgc
65 | *.pgd
66 | *.rsp
67 | *.sbr
68 | *.tlb
69 | *.tli
70 | *.tlh
71 | *.tmp
72 | *.tmp_proj
73 | *.log
74 | *.vspscc
75 | *.vssscc
76 | .builds
77 | *.pidb
78 | *.log
79 | *.scc
80 |
81 | # Visual C++ cache files
82 | ipch/
83 | *.aps
84 | *.ncb
85 | *.opensdf
86 | *.sdf
87 | *.cachefile
88 |
89 | # Visual Studio profiler
90 | *.psess
91 | *.vsp
92 | *.vspx
93 |
94 | # Guidance Automation Toolkit
95 | *.gpState
96 |
97 | # ReSharper is a .NET coding add-in
98 | _ReSharper*/
99 | *.[Rr]e[Ss]harper
100 |
101 | # TeamCity is a build add-in
102 | _TeamCity*
103 |
104 | # DotCover is a Code Coverage Tool
105 | *.dotCover
106 |
107 | # NCrunch
108 | *.ncrunch*
109 | .*crunch*.local.xml
110 |
111 | # Installshield output folder
112 | [Ee]xpress/
113 |
114 | # DocProject is a documentation generator add-in
115 | DocProject/buildhelp/
116 | DocProject/Help/*.HxT
117 | DocProject/Help/*.HxC
118 | DocProject/Help/*.hhc
119 | DocProject/Help/*.hhk
120 | DocProject/Help/*.hhp
121 | DocProject/Help/Html2
122 | DocProject/Help/html
123 |
124 | # Click-Once directory
125 | publish/
126 |
127 | # Publish Web Output
128 | *.Publish.xml
129 | *.pubxml
130 |
131 | # NuGet Packages Directory
132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
133 | #packages/
134 |
135 | # Windows Azure Build Output
136 | csx
137 | *.build.csdef
138 |
139 | # Windows Store app package directory
140 | AppPackages/
141 |
142 | # Others
143 | sql/
144 | *.Cache
145 | ClientBin/
146 | [Ss]tyle[Cc]op.*
147 | ~$*
148 | *~
149 | *.dbmdl
150 | *.[Pp]ublish.xml
151 | *.pfx
152 | *.publishsettings
153 |
154 | # RIA/Silverlight projects
155 | Generated_Code/
156 |
157 | # Backup & report files from converting an old project file to a newer
158 | # Visual Studio version. Backup files are not needed, because we have git ;-)
159 | _UpgradeReport_Files/
160 | Backup*/
161 | UpgradeLog*.XML
162 | UpgradeLog*.htm
163 |
164 | # SQL Server files
165 | App_Data/*.mdf
166 | App_Data/*.ldf
167 |
168 | #############
169 | ## Windows detritus
170 | #############
171 |
172 | # Windows image file caches
173 | Thumbs.db
174 | ehthumbs.db
175 |
176 | # Folder config file
177 | Desktop.ini
178 |
179 | # Recycle Bin used on file shares
180 | $RECYCLE.BIN/
181 |
182 | # Mac crap
183 | .DS_Store
184 |
185 |
186 | #############
187 | ## Python
188 | #############
189 |
190 | *.py[co]
191 |
192 | # Packages
193 | *.egg
194 | *.egg-info
195 | dist/
196 | build/
197 | eggs/
198 | parts/
199 | var/
200 | sdist/
201 | develop-eggs/
202 | .installed.cfg
203 |
204 | # Installer logs
205 | pip-log.txt
206 |
207 | # Unit test / coverage reports
208 | .coverage
209 | .tox
210 |
211 | #Translations
212 | *.mo
213 |
214 | #Mr Developer
215 | .mr.developer.cfg
216 |
217 | ######
218 | # Idea
219 | ######
220 | .idea/
221 |
222 | ##############
223 | # node modules
224 | ##############
225 | node_modules/
226 |
--------------------------------------------------------------------------------
/config/passport.js:
--------------------------------------------------------------------------------
1 | // config/passport.js
2 |
3 | // load all the things we need
4 | var LocalStrategy = require('passport-local').Strategy;
5 |
6 | // load up the user model
7 | var mysql = require('mysql');
8 | var bcrypt = require('bcrypt-nodejs');
9 | var dbconfig = require('./database');
10 | var connection = mysql.createConnection(dbconfig.connection);
11 | connection.connect();
12 | connection.query('USE ' + dbconfig.database);
13 | connection.end();
14 | // expose this function to our app using module.exports
15 | module.exports = function(passport) {
16 |
17 | // =========================================================================
18 | // passport session setup ==================================================
19 | // =========================================================================
20 | // required for persistent login sessions
21 | // passport needs ability to serialize and unserialize users out of session
22 |
23 | // used to serialize the user for the session
24 | passport.serializeUser(function(user, done) {
25 | done(null, user.id);
26 | });
27 |
28 | // used to deserialize the user
29 | passport.deserializeUser(function(id, done) {
30 | connection.connect();
31 | connection.query("SELECT * FROM users WHERE id = ? ",[id], function(err, rows){
32 | done(err, rows[0]);
33 | });
34 | connection.end();
35 | });
36 |
37 | // =========================================================================
38 | // LOCAL SIGNUP ============================================================
39 | // =========================================================================
40 | // we are using named strategies since we have one for login and one for signup
41 | // by default, if there was no name, it would just be called 'local'
42 |
43 | passport.use(
44 | 'local-signup',
45 | new LocalStrategy({
46 | // by default, local strategy uses username and password, we will override with email
47 | usernameField : 'username',
48 | passwordField : 'password',
49 | passReqToCallback : true // allows us to pass back the entire request to the callback
50 | },
51 | function(req, username, password, done) {
52 | // find a user whose email is the same as the forms email
53 | // we are checking to see if the user trying to login already exists
54 | connection.connect();
55 | connection.query("SELECT * FROM users WHERE username = ?",[username], function(err, rows) {
56 | if (err)
57 | return done(err);
58 | if (rows.length) {
59 | return done(null, false, req.flash('signupMessage', 'That username is already taken.'));
60 | } else {
61 | // if there is no user with that username
62 | // create the user
63 | var newUserMysql = {
64 | username: username,
65 | password: bcrypt.hashSync(password, null, null) // use the generateHash function in our user model
66 | };
67 |
68 | var insertQuery = "INSERT INTO users ( username, password ) values (?,?)";
69 | connection.connect();
70 | connection.query(insertQuery,[newUserMysql.username, newUserMysql.password],function(err, rows) {
71 | newUserMysql.id = rows.insertId;
72 |
73 | return done(null, newUserMysql);
74 | });
75 | connection.end();
76 | }
77 | });
78 | connection.end();
79 | })
80 | );
81 |
82 | // =========================================================================
83 | // LOCAL LOGIN =============================================================
84 | // =========================================================================
85 | // we are using named strategies since we have one for login and one for signup
86 | // by default, if there was no name, it would just be called 'local'
87 |
88 | passport.use(
89 | 'local-login',
90 | new LocalStrategy({
91 | // by default, local strategy uses username and password, we will override with email
92 | usernameField : 'username',
93 | passwordField : 'password',
94 | passReqToCallback : true // allows us to pass back the entire request to the callback
95 | },
96 | function(req, username, password, done) { // callback with email and password from our form
97 | connection.connect();
98 | connection.query("SELECT * FROM users WHERE username = ?",[username], function(err, rows){
99 | if (err)
100 | return done(err);
101 | if (!rows.length) {
102 | return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash
103 | }
104 |
105 | // if the user is found but the password is wrong
106 | if (!bcrypt.compareSync(password, rows[0].password))
107 | return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
108 |
109 | // all is well, return successful user
110 | return done(null, rows[0]);
111 | });
112 | connection.end();
113 | })
114 | );
115 | };
116 |
--------------------------------------------------------------------------------