├── README.md ├── .gitignore ├── server ├── auth │ ├── auth-controller.js │ ├── auth-router.js │ └── index.js ├── views │ └── index.html ├── db │ └── index.js └── index.js ├── config └── default.js ├── package.json └── LICENSE /README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | !**/* 2 | node_modules 3 | config/* 4 | !config/default.js 5 | -------------------------------------------------------------------------------- /server/auth/auth-controller.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true */ 2 | 'use strict'; 3 | 4 | var authController = {}; 5 | authController.getUser = function (req, res) { 6 | if (req.user && req.user.id) { 7 | res.json(req.user); 8 | return; 9 | } 10 | res.status(400).json(null); 11 | }; 12 | authController.logout = function (req, res) { 13 | req.logout(); 14 | res.redirect('/'); 15 | }; 16 | 17 | authController.login = function (req, res) { 18 | res.redirect('/'); 19 | }; 20 | 21 | module.exports = authController; 22 | -------------------------------------------------------------------------------- /server/views/index.html: -------------------------------------------------------------------------------- 1 | 2 |

Passport/RethinkDB Example

3 | {{#user}} 4 | 5 |

You are logged in as {{ login }}. Account created through {{ type }}.

6 | See user data 7 |
8 | Logout 9 | {{/user}} 10 | {{^user}} 11 |

You are not logged in.

12 | Login with GitHub 13 |
14 | Login with Twitter 15 | {{/user}} 16 | 17 | -------------------------------------------------------------------------------- /config/default.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | github: { 3 | clientID: '', // Go to github.com, create an application and add clientID 4 | clientSecret: '' // Go to github.com, create an application and add clientSecret 5 | }, 6 | twitter: { 7 | consumerKey: '', // Go to apps.twitter.com, create an application and add consumerKey 8 | consumerSecret: '' // Go to apps.twitter.com, create an application and add consumerSecret 9 | }, 10 | url: '127.0.0.1', 11 | ports: { 12 | http: 8000 13 | }, 14 | rethinkdb: { 15 | host: 'localhost', 16 | port: 28015, 17 | db: 'passport_rethinkdb_tutorial' 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /server/db/index.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true */ 2 | 'use strict'; 3 | 4 | var r = require('rethinkdb'); 5 | require('rethinkdb-init')(r); 6 | var config = require('config'); 7 | 8 | r.connections = []; 9 | r.getNewConnection = function () { 10 | return r.connect(config.get('rethinkdb')) 11 | .then(function (conn) { 12 | conn.use(config.get('rethinkdb').db); 13 | r.connections.push(conn); 14 | return conn; 15 | }); 16 | }; 17 | 18 | r.init(config.get('rethinkdb'), [ 19 | { 20 | name: 'users', 21 | indexes: ['login'] 22 | } 23 | ]).then(function (conn) { 24 | r.conn = conn; 25 | r.connections.push(conn); 26 | r.conn.use(config.get('rethinkdb').db); 27 | }); 28 | 29 | module.exports = r; 30 | -------------------------------------------------------------------------------- /server/auth/auth-router.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true */ 2 | 'use strict'; 3 | 4 | var express = require('express'); 5 | var authControllers = require('./auth-controller'); 6 | 7 | var auth = require('./index'); 8 | var authRouter = express.Router(); 9 | 10 | // GitHub 11 | authRouter.use('/login/callback/github', auth.authenticate('github'), function (req, res) { 12 | res.redirect('/'); 13 | }); 14 | authRouter.get('/login/github', auth.authenticate('github')); 15 | 16 | // Twitter 17 | authRouter.use('/login/callback/twitter', auth.authenticate('twitter'), function (req, res) { 18 | res.redirect('/'); 19 | }); 20 | authRouter.get('/login/twitter', auth.authenticate('twitter')); 21 | 22 | // All 23 | authRouter.use('/user', authControllers.getUser); 24 | authRouter.use('/logout', authControllers.logout); 25 | 26 | module.exports = authRouter; 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passport-rethinkdb-tutorial", 3 | "version": "1.0.0", 4 | "description": "A short tutorial on how to use passport authentication with RethinkDB", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "dev": "./node_modules/nodemon/bin/nodemon.js ./server" 9 | }, 10 | "keywords": [ 11 | "passport", 12 | "rethinkdb", 13 | "authentication", 14 | "oauth" 15 | ], 16 | "author": "thejsj", 17 | "license": "MIT", 18 | "dependencies": { 19 | "config": "^1.12.0", 20 | "consolidate": "^0.12.1", 21 | "express": "^4.12.3", 22 | "express-session": "^1.11.1", 23 | "mustache": "^2.0.0", 24 | "passport": "^0.2.1", 25 | "passport-github": "^0.1.5", 26 | "passport-twitter": "^1.0.3", 27 | "rethinkdb": "^2.0.0", 28 | "rethinkdb-init": "0.0.2" 29 | }, 30 | "devDependencies": { 31 | "nodemon": "^1.3.7" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /server/index.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true */ 2 | 'use strict'; 3 | 4 | var config = require('config'); 5 | var express = require('express'); 6 | var session = require('express-session'); 7 | var engines = require('consolidate'); 8 | 9 | var app = express(); 10 | var auth = require('./auth'); 11 | var authRouter = require('./auth/auth-router'); 12 | 13 | // Middleware 14 | app 15 | .use(session({ 16 | secret: 'zfnzkwjehgweghw', 17 | resave: false, 18 | saveUninitialized: true 19 | })) 20 | .use(auth.initialize()) 21 | .use(auth.session()); 22 | 23 | // Views 24 | app 25 | .set('views', __dirname + '/views') 26 | .engine('html', engines.mustache) 27 | .set('view engine', 'html'); 28 | 29 | // Routes 30 | app 31 | .use('/auth', authRouter) 32 | .get('/', function (req, res) { 33 | res.render('index.html', { user: req.user }); 34 | }) 35 | .use(express.static(__dirname + '/../client')) 36 | .use('*', function (req, res) { 37 | res.status(404).send('404 Not Found').end(); 38 | }); 39 | 40 | app.listen(config.get('ports').http); 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2015 Jorge Silva 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /server/auth/index.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true */ 2 | 'use strict'; 3 | 4 | var config = require('config'); 5 | var passport = require('passport'); 6 | var GitHubStrategy = require('passport-github').Strategy; 7 | var TwitterStrategy = require('passport-twitter').Strategy; 8 | var r = require('../db'); 9 | 10 | passport.serializeUser(function (user, done) { 11 | return done(null, user.id); 12 | }); 13 | 14 | passport.deserializeUser(function (id, done) { 15 | r 16 | .table('users') 17 | .get(id) 18 | .run(r.conn) 19 | .then(function (user) { 20 | done(null, user); 21 | }); 22 | }); 23 | 24 | var loginCallbackHandler = function (objectMapper, type) { 25 | return function (accessToken, refreshToken, profile, done) { 26 | if (accessToken !== null) { 27 | r 28 | .table('users') 29 | .getAll(profile.username, { index: 'login' }) 30 | .filter({ type: type }) 31 | .run(r.conn) 32 | .then(function (cursor) { 33 | return cursor.toArray() 34 | .then(function (users) { 35 | if (users.length > 0) { 36 | return done(null, users[0]); 37 | } 38 | return r.table('users') 39 | .insert(objectMapper(profile)) 40 | .run(r.conn) 41 | .then(function (response) { 42 | return r.table('users') 43 | .get(response.generated_keys[0]) 44 | .run(r.conn); 45 | }) 46 | .then(function (newUser) { 47 | done(null, newUser); 48 | }); 49 | }); 50 | }) 51 | .catch(function (err) { 52 | console.log('Error Getting User', err); 53 | }); 54 | } 55 | }; 56 | }; 57 | var callbackURL = 'http://' + config.get('url') + ':' + config.get('ports').http + '/auth/login/callback'; 58 | 59 | // Github 60 | passport.use(new GitHubStrategy({ 61 | clientID: config.get('github').clientID, 62 | clientSecret: config.get('github').clientSecret, 63 | callbackURL: callbackURL + '/github' 64 | }, 65 | loginCallbackHandler(function (profile) { 66 | return { 67 | 'login': profile.username, 68 | 'name': profile.displayName || null, 69 | 'url': profile.profileUrl, 70 | 'avatarUrl': profile._json.avatar_url, 71 | 'type': 'github' 72 | }; 73 | }, 'github') 74 | )); 75 | 76 | // Twitter 77 | passport.use(new TwitterStrategy({ 78 | consumerKey: config.get('twitter').consumerKey, 79 | consumerSecret: config.get('twitter').consumerSecret, 80 | callbackURL: callbackURL + '/twitter' 81 | }, 82 | loginCallbackHandler(function (profile) { 83 | return { 84 | 'login': profile.username, 85 | 'name': profile.displayName || null, 86 | 'url': profile._raw.expanded_url || null, 87 | 'avatarUrl': profile._json.profile_image_url, 88 | 'type': 'twitter' 89 | }; 90 | }, 'twitter') 91 | )); 92 | 93 | passport.checkIfLoggedIn = function (req, res, next) { 94 | if (req.user) { 95 | return next(); 96 | } 97 | return res.status(401).send('You\'re not logged in'); 98 | }; 99 | 100 | module.exports = passport; 101 | --------------------------------------------------------------------------------