├── .gitignore ├── README.md ├── app ├── authentication │ ├── index.js │ ├── init.js │ └── middleware.js ├── index.js ├── layout.hbs ├── note │ ├── index.js │ ├── init.js │ └── overview.hbs └── user │ ├── index.js │ ├── init.js │ ├── profile.hbs │ └── welcome.hbs ├── config └── index.js ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nodehero-authentication 2 | 3 | 1. `git clone git@github.com:RisingStack/nodehero-authentication.git` 4 | 2. `cd nodehero-authentication` 5 | 3. `npm install` 6 | 4. `REDIS_STORE_URI=redis://localhost REDIS_STORE_SECRET=my-strong-secret npm start` 7 | 8 | ## Pre requirements 9 | 10 | - Running [Redis](https://redis.io/) database 11 | -------------------------------------------------------------------------------- /app/authentication/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | init: require('./init'), 3 | middleware: require('./middleware') 4 | } 5 | -------------------------------------------------------------------------------- /app/authentication/init.js: -------------------------------------------------------------------------------- 1 | const passport = require('passport') 2 | const bcrypt = require('bcrypt') 3 | const LocalStrategy = require('passport-local').Strategy 4 | 5 | const authenticationMiddleware = require('./middleware') 6 | 7 | // Generate Password 8 | const saltRounds = 10 9 | const myPlaintextPassword = 'my-password' 10 | const salt = bcrypt.genSaltSync(saltRounds) 11 | const passwordHash = bcrypt.hashSync(myPlaintextPassword, salt) 12 | 13 | const user = { 14 | username: 'test-user', 15 | passwordHash, 16 | id: 1 17 | } 18 | 19 | function findUser (username, callback) { 20 | if (username === user.username) { 21 | return callback(null, user) 22 | } 23 | return callback(null) 24 | } 25 | 26 | passport.serializeUser(function (user, cb) { 27 | cb(null, user.username) 28 | }) 29 | 30 | passport.deserializeUser(function (username, cb) { 31 | findUser(username, cb) 32 | }) 33 | 34 | function initPassport () { 35 | passport.use(new LocalStrategy( 36 | (username, password, done) => { 37 | findUser(username, (err, user) => { 38 | if (err) { 39 | return done(err) 40 | } 41 | 42 | // User not found 43 | if (!user) { 44 | console.log('User not found') 45 | return done(null, false) 46 | } 47 | 48 | // Always use hashed passwords and fixed time comparison 49 | bcrypt.compare(password, user.passwordHash, (err, isValid) => { 50 | if (err) { 51 | return done(err) 52 | } 53 | if (!isValid) { 54 | return done(null, false) 55 | } 56 | return done(null, user) 57 | }) 58 | }) 59 | } 60 | )) 61 | 62 | passport.authenticationMiddleware = authenticationMiddleware 63 | } 64 | 65 | module.exports = initPassport 66 | -------------------------------------------------------------------------------- /app/authentication/middleware.js: -------------------------------------------------------------------------------- 1 | function authenticationMiddleware () { 2 | return function (req, res, next) { 3 | if (req.isAuthenticated()) { 4 | return next() 5 | } 6 | res.redirect('/') 7 | } 8 | } 9 | 10 | module.exports = authenticationMiddleware 11 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | const express = require('express') 4 | const exphbs = require('express-handlebars') 5 | const bodyParser = require('body-parser') 6 | const passport = require('passport') 7 | const session = require('express-session') 8 | const RedisStore = require('connect-redis')(session) 9 | 10 | const config = require('../config') 11 | const app = express() 12 | 13 | app.use(bodyParser.urlencoded({ 14 | extended: false 15 | })) 16 | 17 | require('./authentication').init(app) 18 | 19 | app.use(session({ 20 | store: new RedisStore({ 21 | url: config.redisStore.url 22 | }), 23 | secret: config.redisStore.secret, 24 | resave: false, 25 | saveUninitialized: false 26 | })) 27 | 28 | app.use(passport.initialize()) 29 | app.use(passport.session()) 30 | 31 | app.engine('.hbs', exphbs({ 32 | defaultLayout: 'layout', 33 | extname: '.hbs', 34 | layoutsDir: path.join(__dirname), 35 | partialsDir: path.join(__dirname) 36 | })) 37 | 38 | app.set('view engine', '.hbs') 39 | app.set('views', path.join(__dirname)) 40 | 41 | require('./user').init(app) 42 | require('./note').init(app) 43 | 44 | module.exports = app 45 | -------------------------------------------------------------------------------- /app/layout.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Node Hero - Authentication Tutorial 5 | 6 | 7 | 8 | 9 | {{{body}}} 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/note/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | init: require('./init') 3 | } 4 | -------------------------------------------------------------------------------- /app/note/init.js: -------------------------------------------------------------------------------- 1 | const passport = require('passport') 2 | 3 | function initUser (app) { 4 | app.get('/notes/:id', passport.authenticationMiddleware(), (req, res) => { 5 | res.render('note/overview', { 6 | id: req.params.id 7 | }) 8 | }) 9 | } 10 | 11 | module.exports = initUser 12 | -------------------------------------------------------------------------------- /app/note/overview.hbs: -------------------------------------------------------------------------------- 1 |

Note #{{id}}

2 | 3 | Lorem ipsum... 4 | -------------------------------------------------------------------------------- /app/user/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | init: require('./init') 3 | } 4 | -------------------------------------------------------------------------------- /app/user/init.js: -------------------------------------------------------------------------------- 1 | const passport = require('passport') 2 | 3 | function initUser (app) { 4 | app.get('/', renderWelcome) 5 | app.get('/profile', passport.authenticationMiddleware(), renderProfile) 6 | app.post('/login', passport.authenticate('local', { 7 | successRedirect: '/profile', 8 | failureRedirect: '/' 9 | })) 10 | } 11 | 12 | function renderWelcome (req, res) { 13 | res.render('user/welcome') 14 | } 15 | 16 | function renderProfile (req, res) { 17 | res.render('user/profile', { 18 | username: req.user.username 19 | }) 20 | } 21 | 22 | module.exports = initUser 23 | -------------------------------------------------------------------------------- /app/user/profile.hbs: -------------------------------------------------------------------------------- 1 |

Hey, {{username}}!

2 | 3 | You successfully logged-in \o/ 4 | -------------------------------------------------------------------------------- /app/user/welcome.hbs: -------------------------------------------------------------------------------- 1 |

Hey! You have to log in before using NodeHero :/

2 | 3 |
4 | 5 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | const config = {} 2 | 3 | config.redisStore = { 4 | url: process.env.REDIS_STORE_URI, 5 | secret: process.env.REDIS_STORE_SECRET 6 | } 7 | 8 | module.exports = config 9 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const app = require('./app') 2 | const port = process.env.PORT || 3000 3 | 4 | app.listen(port, function (err) { 5 | if (err) { 6 | throw err 7 | } 8 | 9 | console.log(`server is listening on ${port}...`) 10 | }) 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@risingstack/nodehero-authentication", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "node index.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/RisingStack/nodehero-authentication.git" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "bugs": { 18 | "url": "https://github.com/RisingStack/nodehero-authentication/issues" 19 | }, 20 | "homepage": "https://github.com/RisingStack/nodehero-authentication#readme", 21 | "dependencies": { 22 | "bcrypt": "1.0.2", 23 | "body-parser": "1.15.1", 24 | "connect-redis": "3.0.2", 25 | "express": "4.13.4", 26 | "express-handlebars": "3.0.0", 27 | "express-session": "1.13.0", 28 | "passport": "0.3.2", 29 | "passport-local": "1.0.0" 30 | } 31 | } 32 | --------------------------------------------------------------------------------