├── views ├── partials │ └── footer.ejs ├── success.ejs ├── template │ ├── index.html │ ├── profile.html │ ├── login.html │ └── signup.html ├── bare_templates │ ├── login.html │ └── register.html ├── index.ejs ├── profile.ejs ├── signup.ejs ├── login.ejs └── forgot-password.ejs ├── .gitignore ├── config ├── monkoKEY.js └── googleData.js ├── .gitattributes ├── screenshots ├── reset_password_added.png ├── change_password_option.png ├── alert_with_working_email_send.png └── error_flash_on_accessing_unauthenticated_routes.png ├── model ├── resetTokens.js └── user.js ├── package.json ├── controller ├── sendMail.js ├── passportLocal.js ├── googleAuth.js ├── routes.js └── accountRoutes.js ├── README.md └── index.js /views/partials/footer.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | node_modules -------------------------------------------------------------------------------- /config/monkoKEY.js: -------------------------------------------------------------------------------- 1 | module.exports = ""; -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-vendored 2 | *.js linguist-vendored=false 3 | -------------------------------------------------------------------------------- /config/googleData.js: -------------------------------------------------------------------------------- 1 | module.exports.clientId = ""; 2 | module.exports.clientSecret = ""; -------------------------------------------------------------------------------- /screenshots/reset_password_added.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desi-programmer/nodejs_authentication/HEAD/screenshots/reset_password_added.png -------------------------------------------------------------------------------- /screenshots/change_password_option.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desi-programmer/nodejs_authentication/HEAD/screenshots/change_password_option.png -------------------------------------------------------------------------------- /screenshots/alert_with_working_email_send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desi-programmer/nodejs_authentication/HEAD/screenshots/alert_with_working_email_send.png -------------------------------------------------------------------------------- /screenshots/error_flash_on_accessing_unauthenticated_routes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/desi-programmer/nodejs_authentication/HEAD/screenshots/error_flash_on_accessing_unauthenticated_routes.png -------------------------------------------------------------------------------- /model/resetTokens.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const resetTokens = new mongoose.Schema({ 4 | token: { 5 | type: String, 6 | required: true, 7 | }, 8 | email: { 9 | type: String, 10 | required: true, 11 | }, 12 | created: { 13 | type: Date, 14 | default: () => Date.now(), 15 | }, 16 | // will automatically delete after 10 min 17 | // can be a bit delay, because the bg thread runs every 60 sec 18 | expire_at: { type: Date, default: Date.now, expires: 600 } 19 | }); 20 | 21 | module.exports = mongoose.model('resetTokens', resetTokens); -------------------------------------------------------------------------------- /model/user.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const userSchema = new mongoose.Schema({ 4 | username: { 5 | type: String, 6 | required: true, 7 | }, 8 | email: { 9 | type: String, 10 | required: true, 11 | }, 12 | password: { 13 | type: String, 14 | }, 15 | 16 | isVerified: { 17 | type: Boolean, 18 | default: false, 19 | }, 20 | 21 | googleId: { 22 | type: String, 23 | }, 24 | provider: { 25 | type: String, 26 | required: true, 27 | } 28 | }); 29 | 30 | module.exports = mongoose.model('user', userSchema); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "authentications", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon index", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "bcryptjs": "^2.4.3", 15 | "connect-flash": "^0.1.1", 16 | "cookie-parser": "^1.4.5", 17 | "csurf": "^1.11.0", 18 | "ejs": "^3.1.5", 19 | "express": "^4.17.1", 20 | "express-session": "^1.17.1", 21 | "memorystore": "^1.6.4", 22 | "mongoose": "^5.11.13", 23 | "nodemailer": "^6.5.0", 24 | "passport": "^0.4.1", 25 | "passport-google-oauth20": "^2.0.0", 26 | "passport-local": "^1.0.0" 27 | }, 28 | "devDependencies": { 29 | "nodemon": "^2.0.7" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /controller/sendMail.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require("nodemailer"); 2 | 3 | var smtpTransport = nodemailer.createTransport({ 4 | service: "gmail", 5 | auth: { 6 | user: "", 7 | pass: "", 8 | }, 9 | }); 10 | 11 | module.exports.sendResetEmail = async (email, token) => { 12 | // change first part to your domain 13 | var url = "http://localhost:8000/user/reset-password?token=" + token; 14 | 15 | await smtpTransport.sendMail({ 16 | from: "", 17 | to: email, 18 | subject: "RESET YOUR PASSWORD", 19 | text: `Click on this link to reset your password ${url}`, 20 | html: `

Click on this link to reset your password : ${url}

`, 21 | }); 22 | }; 23 | 24 | module.exports.sendVerifyEmail = async (email, token) => { 25 | // change first part to your domain 26 | var url = "http://localhost:8000/user/verifyemail?token=" + token; 27 | 28 | await smtpTransport.sendMail({ 29 | from: "", 30 | to: email, 31 | subject: "VERIFY Your EMAIL", 32 | text: `Click on this link to verify ${url}`, 33 | html: `

Click on this link to verify your email : ${url}

`, 34 | }); 35 | }; 36 | -------------------------------------------------------------------------------- /controller/passportLocal.js: -------------------------------------------------------------------------------- 1 | const user = require('../model/user'); 2 | const bcryptjs = require('bcryptjs'); 3 | var localStrategy = require('passport-local').Strategy; 4 | 5 | module.exports = function (passport) { 6 | passport.use(new localStrategy({ usernameField: 'email' }, (email, password, done) => { 7 | user.findOne({ email: email }, (err, data) => { 8 | if (err) throw err; 9 | if (!data) { 10 | return done(null, false, { message: "User Doesn't Exist !" }); 11 | } 12 | bcryptjs.compare(password, data.password, (err, match) => { 13 | if (err) { 14 | return done(null, false); 15 | } 16 | if (!match) { 17 | return done(null, false, { message: "Password Doesn't match !" }); 18 | } 19 | if (match) { 20 | return done(null, data); 21 | } 22 | }) 23 | }) 24 | })); 25 | 26 | passport.serializeUser(function (user, done) { 27 | done(null, user.id); 28 | }); 29 | 30 | passport.deserializeUser(function (id, done) { 31 | user.findById(id, function (err, user) { 32 | done(err, user); 33 | }); 34 | }); 35 | 36 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node Passport Authentication 2 | 3 | This repo contains code for Local email-passport authentication and Google Authentication. 4 | 5 | ## Blog (Local Auth) : [Here](https://desiprogrammer.com/blogs/node-express-passport-email-authentication) 6 | 7 | ## Blog (Google Auth) : [Here](https://desiprogrammer.com/blogs/nodejs-express-google-authentication) 8 | 9 | ## Tutorial (Local Auth) : [Here](https://www.youtube.com/watch?v=-ZxXS9gsWX4) 10 | 11 | ## Tutorial (Google Auth) : [Here](https://www.youtube.com/watch?v=d-IToO3gLrM) 12 | 13 | ## 1. USAGE 14 | 15 | ### Install All Packages 16 | 17 | ```bash 18 | npm install express ejs mongoose bcryptjs connect-flash cookie-parser express-session csurf memorystore passport passport-local passport-google-oauth20 nodemailer 19 | ``` 20 | 21 | ### Install Nodemon For Development 22 | 23 | ```bash 24 | npm install -D nodemon 25 | ``` 26 | 27 | ### Add mongoURI ,Google client ID and Secret, smtp config for sending emails 28 | ### And Feel free to delete the screenshots directory 29 | 30 | # Added Options 31 | 32 | ![Image1](screenshots/error_flash_on_accessing_unauthenticated_routes.png) 33 | ![Image2](screenshots/reset_password_added.png) 34 | ![Image3](screenshots/change_password_option.png) 35 | ![Image4](screenshots/alert_with_working_email_send.png) 36 | 37 | # Todo ( ✔ -> Done ) 38 | 39 | ✔ Add User Password rest 40 | ✔ Add Verify Account 41 | ✔ Add Email Sending Options 42 | ✔ Added Flash messages for errors 43 | 44 | 45 | -------------------------------------------------------------------------------- /views/success.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Success 10 | 11 | 12 | 13 |
14 |

Welcome <%= user.username %>

15 |

If You See This Page
Then You Have Logged In Successfully !

16 | Logout 17 |
18 |
19 |
20 | 22 |
23 |
24 | 25 |
26 |
27 | <% user.messages.forEach(function(msg, index){ %> 28 |

<%= msg %>

29 | <% }) %> 30 |
31 |
32 |

33 |

34 |
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const mongoose = require('mongoose'); 3 | const csrf = require('csurf'); 4 | const cookieParser = require('cookie-parser'); 5 | const expressSession = require('express-session'); 6 | const MemoryStore = require('memorystore')(expressSession) 7 | const passport = require('passport'); 8 | const flash = require('connect-flash'); 9 | 10 | const app = express(); 11 | 12 | app.set('view engine', 'ejs'); 13 | app.set('views', __dirname + '/views',); 14 | 15 | app.use(express.urlencoded({ extended: true })); 16 | 17 | const mongoURI = require('./config/monkoKEY'); 18 | mongoose.connect(mongoURI, { useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false, useCreateIndex: true, },).then(() => console.log("Connected !"),); 19 | 20 | app.use(cookieParser('random')); 21 | 22 | app.use(expressSession({ 23 | secret: "random", 24 | resave: true, 25 | saveUninitialized: true, 26 | // setting the max age to longer duration 27 | maxAge: 24 * 60 * 60 * 1000, 28 | store: new MemoryStore(), 29 | })); 30 | 31 | app.use(csrf()); 32 | app.use(passport.initialize()); 33 | app.use(passport.session()); 34 | 35 | app.use(flash()); 36 | 37 | app.use(function (req, res, next) { 38 | res.locals.success_messages = req.flash('success_messages'); 39 | res.locals.error_messages = req.flash('error_messages'); 40 | res.locals.error = req.flash('error'); 41 | next(); 42 | }); 43 | 44 | app.use(require('./controller/routes.js')); 45 | 46 | const PORT = process.env.PORT || 8000; 47 | 48 | app.listen(PORT, () => console.log("Server Started At " + PORT)); -------------------------------------------------------------------------------- /controller/googleAuth.js: -------------------------------------------------------------------------------- 1 | var GoogleStrategy = require('passport-google-oauth20').Strategy; 2 | const user = require('../model/user'); 3 | const clientId = require('../config/googleData').clientId; 4 | const clientSecreT = require('../config/googleData').clientSecret; 5 | 6 | module.exports = function (passport) { 7 | passport.use(new GoogleStrategy({ 8 | clientID: clientId, 9 | clientSecret: clientSecreT, 10 | callbackURL: "http://localhost:8000/google/callback" 11 | }, (accessToken, refreshToken, profile, done) => { 12 | console.log(profile.emails[0].value); 13 | 14 | // find if a user exist with this email or not 15 | user.findOne({ email: profile.emails[0].value }).then((data) => { 16 | if (data) { 17 | // user exists 18 | // update data 19 | // I am skipping that part here, may Update Later 20 | return done(null, data); 21 | } else { 22 | // create a user 23 | user({ 24 | username: profile.displayName, 25 | email: profile.emails[0].value, 26 | googleId: profile.id, 27 | password: null, 28 | provider: 'google', 29 | isVerified: true, 30 | }).save(function (err, data) { 31 | return done(null, data); 32 | }); 33 | } 34 | }); 35 | } 36 | )); 37 | passport.serializeUser(function (user, done) { 38 | done(null, user.id); 39 | }); 40 | 41 | passport.deserializeUser(function (id, done) { 42 | user.findById(id, function (err, user) { 43 | done(err, user); 44 | }); 45 | }); 46 | 47 | } -------------------------------------------------------------------------------- /views/template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Authentications 13 | 14 | 20 | 21 | 22 | 23 | 45 | 46 | 47 |
48 |

Welcome To Desi Programmer

49 |

This is a Tutorial About Node Js Authentication and Authorization

50 |
51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /views/bare_templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Authentications 10 | 16 | 17 | 18 | 19 |
20 |

Login Here

21 |
22 |
23 |
24 | 25 | 27 |
28 |
29 | 30 | 32 |
33 |
34 | 35 |
36 |

New Here ? Register Now

37 |
38 |
39 |
40 | 41 | 44 | 47 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | Authentications 16 | 17 | 23 | 24 | 25 | 26 | 27 | 55 | 56 | 57 |
58 |

Welcome To Desi Programmer

59 |

This is a Tutorial About Node Js Authentication and Authorization

60 |
61 | 62 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /views/template/profile.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Authentications 14 | 26 | 27 | 28 | 29 | 30 | 31 | 53 | 54 | 55 | 56 |
57 |

Your Profile

58 | 59 |
60 | ... 61 |
62 |

username

63 | 64 |
65 |
66 | 67 |
68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /views/bare_templates/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Authentications 10 | 16 | 17 | 18 | 19 |
20 |

Register Yourself

21 |
22 |
23 |
24 | 25 | 27 |
28 |
29 | 30 | 32 |
33 |
34 | 35 | 37 |
38 |
39 | 40 | 42 |
43 |
44 | 45 |
46 |

Already Registered ? LOGIN Here

47 |
48 |
49 |
50 | 53 | 56 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /views/template/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | Authentications 14 | 26 | 27 | 28 | 29 | 30 | 31 | 53 | 54 | 55 | 56 |
57 |

Login Here

58 |
59 |
60 |
61 | 62 | 64 |
65 |
66 | 67 | 69 |
70 |
71 | 72 | Continue With Google 73 |
74 |

New Here ? Register Now

75 |
76 |
77 |
78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /controller/routes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const user = require('../model/user'); 4 | const bcryptjs = require('bcryptjs'); 5 | const passport = require('passport'); 6 | require('./passportLocal')(passport); 7 | require('./googleAuth')(passport); 8 | const userRoutes = require('./accountRoutes'); 9 | 10 | function checkAuth(req, res, next) { 11 | if (req.isAuthenticated()) { 12 | res.set('Cache-Control', 'no-cache, private, no-store, must-revalidate, post-check=0, pre-check=0'); 13 | next(); 14 | } else { 15 | req.flash('error_messages', "Please Login to continue !"); 16 | res.redirect('/login'); 17 | } 18 | } 19 | 20 | router.get('/', (req, res) => { 21 | if (req.isAuthenticated()) { 22 | res.render("index", { logged: true }); 23 | } else { 24 | res.render("index", { logged: false }); 25 | } 26 | }); 27 | 28 | router.get('/login', (req, res) => { 29 | res.render("login", { csrfToken: req.csrfToken() }); 30 | }); 31 | 32 | router.get('/signup', (req, res) => { 33 | res.render("signup", { csrfToken: req.csrfToken() }); 34 | }); 35 | 36 | router.post('/signup', (req, res) => { 37 | // get all the values 38 | const { email, username, password, confirmpassword } = req.body; 39 | // check if the are empty 40 | if (!email || !username || !password || !confirmpassword) { 41 | res.render("signup", { err: "All Fields Required !", csrfToken: req.csrfToken() }); 42 | } else if (password != confirmpassword) { 43 | res.render("signup", { err: "Password Don't Match !", csrfToken: req.csrfToken() }); 44 | } else { 45 | 46 | // validate email and username and password 47 | // skipping validation 48 | // check if a user exists 49 | user.findOne({ $or: [{ email: email }, { username: username }] }, function (err, data) { 50 | if (err) throw err; 51 | if (data) { 52 | res.render("signup", { err: "User Exists, Try Logging In !", csrfToken: req.csrfToken() }); 53 | } else { 54 | // generate a salt 55 | bcryptjs.genSalt(12, (err, salt) => { 56 | if (err) throw err; 57 | // hash the password 58 | bcryptjs.hash(password, salt, (err, hash) => { 59 | if (err) throw err; 60 | // save user in db 61 | user({ 62 | username: username, 63 | email: email, 64 | password: hash, 65 | googleId: null, 66 | provider: 'email', 67 | }).save((err, data) => { 68 | if (err) throw err; 69 | // login the user 70 | // use req.login 71 | // redirect , if you don't want to login 72 | res.redirect('/login'); 73 | }); 74 | }) 75 | }); 76 | } 77 | }); 78 | } 79 | }); 80 | 81 | router.post('/login', (req, res, next) => { 82 | passport.authenticate('local', { 83 | failureRedirect: '/login', 84 | successRedirect: '/profile', 85 | failureFlash: true, 86 | })(req, res, next); 87 | }); 88 | 89 | router.get('/logout', (req, res) => { 90 | req.logout(); 91 | req.session.destroy(function (err) { 92 | res.redirect('/'); 93 | }); 94 | }); 95 | 96 | router.get('/google', passport.authenticate('google', { scope: ['profile', 'email',] })); 97 | 98 | router.get('/google/callback', passport.authenticate('google', { failureRedirect: '/login' }), (req, res) => { 99 | res.redirect('/profile'); 100 | }); 101 | 102 | router.get('/profile', checkAuth, (req, res) => { 103 | // adding a new parameter for checking verification 104 | res.render('profile', { username: req.user.username, verified : req.user.isVerified }); 105 | 106 | }); 107 | 108 | 109 | router.use(userRoutes); 110 | 111 | module.exports = router; -------------------------------------------------------------------------------- /views/template/signup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | Authentications 15 | 26 | 27 | 28 | 29 | 30 | 31 | 54 | 55 | 56 | 57 |
58 |

Register Yourself

59 |
60 |
61 |
62 | 63 | 65 |
66 |
67 | 68 | 70 |
71 |
72 | 73 | 75 |
76 |
77 | 78 | 80 |
81 |
82 | 83 | Continue With Google 84 |
85 |

Already Registered ? LOGIN Here

86 |
87 |
88 |
89 | 90 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /views/profile.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | Authentications 15 | 26 | 27 | 28 | 29 | 30 | 31 | 51 | 52 | 53 | 54 |
55 | 56 | 57 | <% if(!verified){ %> 58 | 64 | <% } %> 65 | 66 | <% if(typeof emailsent !='undefined' ){ %> 67 | <% if(emailsent){ %> 68 | 73 | 74 | <% } %> 75 | <% } %> 76 | <% if(typeof err !='undefined' ){ %> 77 | <% if(err){ %> 78 | 84 | 85 | <% } %> 86 | <% } %> 87 | 88 |

Your Profile

89 | 90 |
91 | ... 94 |
95 |

96 | <%= username %> 97 |

98 | 99 |
100 |
101 | 102 |
103 | 104 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /views/signup.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | Authentications 15 | 26 | 27 | 28 | 29 | 30 | 31 | 54 | 55 | 56 | 57 |
58 |

Register Yourself

59 |
60 | 61 | <% if(typeof err !='undefined' ){ %> 62 | 67 | <% } %> 68 | 69 |
70 | 71 |
72 | 73 | 75 |
76 |
77 | 78 | 80 |
81 |
82 | 83 | 85 |
86 |
87 | 88 | 90 |
91 |
92 | 93 | Continue With Google 94 |
95 |

Already Registered ? LOGIN Here

96 |
97 |
98 |
99 | 100 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /views/login.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 20 | Authentications 21 | 32 | 33 | 34 | 35 | 36 | 65 | 66 | 67 |
68 |

Login Here

69 |
73 | <% if( error !="" ){ %> 74 | 87 | <% } %> 88 | 89 | 90 | 91 | 92 | <% if( error_messages !="" ){ %> 93 | 98 | <% } %> 99 | 100 |
101 | 102 |
103 | 104 | 112 |
113 |
114 | 115 | 123 |
124 |
125 | 130 | Continue With Google 133 |
134 |

New Here ? Register Now

135 | 136 |

137 | Forgot Password 140 |

141 |
142 |
143 |
144 | 145 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /views/forgot-password.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 20 | Authentications 21 | 32 | 33 | 34 | 35 | 36 | 65 | 66 | 67 |
68 |

Reset Your Password

69 |
73 | <% if(typeof reset !='undefined' ){ %> <% if( reset){ %> <% if(typeof 74 | err !='undefined' ){ %> <% if( err !="" ){ %> 75 | 88 | <% } %> <% } %> 89 | 90 | 91 |
92 | 93 |
94 | 95 | 103 |
104 |
105 | 106 | 114 |
115 | 116 |
117 | 122 |
123 |
124 | 125 | <% }else{ %> <% } %> <% }else{ %> 126 | 127 | 128 | <% if(typeof msg !='undefined' ){ %> <% if( msg !="" ){ %> 129 | 142 | <% } %> <% } %> 143 | 144 |
145 | 146 |
147 | 148 | 156 |
157 | 158 |
159 | 164 |
165 |
166 | <% } %> 167 |
168 |
169 | 170 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /controller/accountRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const crypto = require('crypto'); 4 | const resetToken = require('../model/resetTokens'); 5 | const user = require('../model/user'); 6 | const mailer = require('./sendMail'); 7 | const bcryptjs = require('bcryptjs'); 8 | 9 | function checkAuth(req, res, next) { 10 | if (req.isAuthenticated()) { 11 | res.set('Cache-Control', 'no-cache, private, no-store, must-revalidate, post-check=0, pre-check=0'); 12 | next(); 13 | } else { 14 | req.flash('error_messages', "Please Login to continue !"); 15 | res.redirect('/login'); 16 | } 17 | } 18 | 19 | // adding the checkAuth middleware to make sure that 20 | // only authenticated users can send emails 21 | router.get('/user/send-verification-email', checkAuth, async (req, res) => { 22 | // check if user is google or already verified 23 | if (req.user.isVerified || req.user.provider == 'google') { 24 | // already verified or google user 25 | // since we won't show any such option in the UI 26 | // most probably this is being called by mistake or can be an attack 27 | // simply redirect to profile 28 | res.redirect('/profile'); 29 | } else { 30 | // generate a token 31 | var token = crypto.randomBytes(32).toString('hex'); 32 | // add that to database 33 | await resetToken({ token: token, email: req.user.email }).save(); 34 | // send an email for verification 35 | mailer.sendVerifyEmail(req.user.email, token); 36 | res.render('profile', { username: req.user.username, verified: req.user.isVerified, emailsent: true }); 37 | } 38 | }); 39 | 40 | 41 | router.get('/user/verifyemail', async (req, res) => { 42 | // grab the token 43 | const token = req.query.token; 44 | // check if token exists 45 | // or just send an error 46 | if (token) { 47 | var check = await resetToken.findOne({ token: token }); 48 | if (check) { 49 | // token verified 50 | // set the property of verified to true for the user 51 | var userData = await user.findOne({ email: check.email }); 52 | userData.isVerified = true; 53 | await userData.save(); 54 | // delete the token now itself 55 | await resetToken.findOneAndDelete({ token: token }); 56 | res.redirect('/profile'); 57 | } else { 58 | res.render('profile', { username: req.user.username, verified: req.user.isVerified, err: "Invalid token or Token has expired, Try again." }); 59 | } 60 | } else { 61 | // doesnt have a token 62 | // I will simply redirect to profile 63 | res.redirect('/profile'); 64 | } 65 | }); 66 | 67 | router.get('/user/forgot-password', async (req, res) => { 68 | // render reset password page 69 | // not checking if user is authenticated 70 | // so that you can use as an option to change password too 71 | res.render('forgot-password.ejs', { csrfToken: req.csrfToken() }); 72 | 73 | }); 74 | 75 | router.post('/user/forgot-password', async (req, res) => { 76 | const { email } = req.body; 77 | // not checking if the field is empty or not 78 | // check if a user existss with this email 79 | var userData = await user.findOne({ email: email }); 80 | console.log(userData); 81 | if (userData) { 82 | if (userData.provider == 'google') { 83 | // type is for bootstrap alert types 84 | res.render('forgot-password.ejs', { csrfToken: req.csrfToken(), msg: "User exists with Google account. Try resetting your google account password or logging using it.", type: 'danger' }); 85 | } else { 86 | // user exists and is not with google 87 | // generate token 88 | var token = crypto.randomBytes(32).toString('hex'); 89 | // add that to database 90 | await resetToken({ token: token, email: email }).save(); 91 | // send an email for verification 92 | mailer.sendResetEmail(email, token); 93 | 94 | res.render('forgot-password.ejs', { csrfToken: req.csrfToken(), msg: "Reset email sent. Check your email for more info.", type: 'success' }); 95 | } 96 | } else { 97 | res.render('forgot-password.ejs', { csrfToken: req.csrfToken(), msg: "No user Exists with this email.", type: 'danger' }); 98 | 99 | } 100 | }); 101 | 102 | router.get('/user/reset-password', async (req, res) => { 103 | // do as in user verify , first check for a valid token 104 | // and if the token is valid send the forgot password page to show the option to change password 105 | 106 | const token = req.query.token; 107 | if (token) { 108 | var check = await resetToken.findOne({ token: token }); 109 | if (check) { 110 | // token verified 111 | // send forgot-password page with reset to true 112 | // this will render the form to reset password 113 | // sending token too to grab email later 114 | res.render('forgot-password.ejs', { csrfToken: req.csrfToken(), reset: true, email: check.email }); 115 | } else { 116 | res.render('forgot-password.ejs', { csrfToken: req.csrfToken(), msg: "Token Tampered or Expired.", type: 'danger' }); 117 | } 118 | } else { 119 | // doesnt have a token 120 | // I will simply redirect to profile 121 | res.redirect('/login'); 122 | } 123 | 124 | }); 125 | 126 | 127 | router.post('/user/reset-password', async (req, res) => { 128 | // get passwords 129 | const { password, password2, email } = req.body; 130 | console.log(password); 131 | console.log(password2); 132 | if (!password || !password2 || (password2 != password)) { 133 | res.render('forgot-password.ejs', { csrfToken: req.csrfToken(), reset: true, err: "Passwords Don't Match !", email: email }); 134 | } else { 135 | // encrypt the password 136 | var salt = await bcryptjs.genSalt(12); 137 | if (salt) { 138 | var hash = await bcryptjs.hash(password, salt); 139 | await user.findOneAndUpdate({ email: email }, { $set: { password: hash } }); 140 | res.redirect('/login'); 141 | } else { 142 | res.render('forgot-password.ejs', { csrfToken: req.csrfToken(), reset: true, err: "Unexpected Error Try Again", email: email }); 143 | 144 | } 145 | } 146 | }); 147 | 148 | 149 | module.exports = router; --------------------------------------------------------------------------------