├── .gitignore ├── README.md ├── app.js ├── config ├── oauth.js └── passport.js ├── facebook.md ├── models ├── index.js └── user.js ├── package.json ├── public ├── index.html ├── js │ ├── app.js │ └── controllers.js └── views │ ├── home.html │ ├── login.html │ ├── profile.html │ └── signup.html ├── routes └── auth.js └── sample.env /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Passport Authentication with Express and Angular 2 | A quick source code tutorial for adding passport authentication to a MEAN stack app 3 | 4 | First create an express app, you'll need the following node packages in your package.json: 5 | 6 | ``` 7 | "dependencies": { 8 | "bcrypt-nodejs": "0.0.3", 9 | "body-parser": "^1.14.2", 10 | "cookie-parser": "^1.4.0", 11 | "express": "^4.13.3", 12 | "express-session": "^1.12.1", 13 | "mongoose": "^4.3.4", 14 | "morgan": "^1.6.1", 15 | "passport": "^0.3.2", 16 | "passport-local": "^1.0.0" 17 | } 18 | ``` 19 | 20 | Now structure your app as follows: 21 | 22 | ``` 23 | -- app_name 24 | ---- config 25 | -------- passport.js 26 | ---- models 27 | -------- index.js 28 | -------- user.js 29 | ---- public 30 | ------ js 31 | ---------- app.js 32 | ---------- controllers.js 33 | ------ views 34 | ---------- home.html 35 | ---------- login.html 36 | ---------- profile.html 37 | ---------- signup.html 38 | ------ index.html 39 | ---- routes 40 | -------- auth.js 41 | ---- .gitignore 42 | ---- app.js 43 | ---- package.json 44 | ``` 45 | 46 | Be sure to add `node_modules` to your .gitignore 47 | 48 | Now let's handle our backend code: 49 | 50 | in `app_name -> app.js` add the following code: 51 | 52 | ```js 53 | //Express 54 | var express = require('express'); 55 | var app = express(); 56 | app.use(express.static(__dirname + '/public')); 57 | 58 | //Passport 59 | var passport = require('passport'); 60 | require('./config/passport')(passport); // pass passport for configuration 61 | 62 | //Cookie and session 63 | var cookieParser = require('cookie-parser'); 64 | var session = require('express-session'); 65 | app.use(session({ 66 | secret: 'this is the secret' 67 | })); 68 | app.use(cookieParser()); 69 | app.use(passport.initialize()); 70 | app.use(passport.session()); 71 | 72 | //Body-parser 73 | var bodyParser = require('body-parser'); 74 | app.use(bodyParser.json()); //for parsing application/json 75 | app.use(bodyParser.urlencoded({ 76 | extended: true 77 | })); 78 | 79 | // routes ====================================================================== 80 | require('./routes/auth.js')(app, passport); // load our routes and pass in our app and fully configured passport 81 | 82 | 83 | app.listen(3000); 84 | ``` 85 | 86 | In your `routes -> auth.js` add the following: 87 | 88 | ```js 89 | var db = require("../models"); 90 | 91 | module.exports = function(app, passport) { 92 | // process the login form 93 | app.post("/login", passport.authenticate('local-login'), function(req, res) { 94 | res.json(req.user); 95 | }); 96 | 97 | // handle logout 98 | app.post("/logout", function(req, res) { 99 | req.logOut(); 100 | res.send(200); 101 | }) 102 | 103 | // loggedin 104 | app.get("/loggedin", function(req, res) { 105 | res.send(req.isAuthenticated() ? req.user : '0'); 106 | }); 107 | 108 | // signup 109 | app.post("/signup", function(req, res) { 110 | db.User.findOne({ 111 | username: req.body.username 112 | }, function(err, user) { 113 | if (user) { 114 | res.json(null); 115 | return; 116 | } else { 117 | var newUser = new db.User(); 118 | newUser.username = req.body.username.toLowerCase(); 119 | newUser.password = newUser.generateHash(req.body.password); 120 | newUser.save(function(err, user) { 121 | req.login(user, function(err) { 122 | if (err) { 123 | return next(err); 124 | } 125 | res.json(user); 126 | }); 127 | }); 128 | } 129 | }); 130 | }); 131 | }; 132 | ``` 133 | 134 | Now let's configure passport, we'll use the passport.js file to abstract some of the logic away from our main server file, thus modularizing and cleaning up our code a bit. Open up `config -> passport.js` and add the following: 135 | 136 | ```js 137 | // load all the things we need 138 | var LocalStrategy = require('passport-local').Strategy; 139 | 140 | // load up the user model 141 | var User = require('../models/user'); 142 | 143 | // expose this function to our app using module.exports 144 | module.exports = function(passport) { 145 | 146 | passport.serializeUser(function(user, done) { 147 | done(null, user); 148 | }); 149 | 150 | passport.deserializeUser(function(user, done) { 151 | done(null, user); 152 | }); 153 | 154 | passport.use('local-login', new LocalStrategy( 155 | function(username, password, done) { 156 | User.findOne({ 157 | username: username.toLowerCase() 158 | }, function(err, user) { 159 | // if there are any errors, return the error before anything else 160 | if (err) 161 | return done(err); 162 | 163 | // if no user is found, return the message 164 | if (!user) 165 | return done(null, false); 166 | 167 | // if the user is found but the password is wrong 168 | if (!user.validPassword(password)) 169 | return done(null, false); 170 | 171 | // all is well, return successful user 172 | return done(null, user); 173 | }); 174 | } 175 | )); 176 | }; 177 | ``` 178 | 179 | Now let's connect to our database and build out a schema for our user model. Open up `models -> index.js` and add the following: 180 | 181 | ```js 182 | var mongoose = require("mongoose"); 183 | mongoose.connect("mongodb://localhost/passport-db"); 184 | 185 | mongoose.set("debug", true); 186 | 187 | module.exports.User = require("./user"); 188 | ``` 189 | 190 | now open up `models -> user.js` and add the code below: 191 | 192 | ```js 193 | // load the things we need 194 | var mongoose = require('mongoose'); 195 | var bcrypt = require('bcrypt-nodejs'); 196 | 197 | // define the schema for our user model 198 | var userSchema = mongoose.Schema({ 199 | username: String, 200 | password: String 201 | }); 202 | 203 | // methods ====================== 204 | // generating a hash 205 | userSchema.methods.generateHash = function(password) { 206 | return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null); 207 | }; 208 | 209 | // checking if password is valid 210 | userSchema.methods.validPassword = function(password) { 211 | return bcrypt.compareSync(password, this.password); 212 | }; 213 | 214 | // create the model for users and expose it to our app 215 | module.exports = mongoose.model('User', userSchema); 216 | ``` 217 | 218 | You can see where we've used bcrypt to generate a hash and validate passwords on signup and login, respectively. 219 | 220 | That's it for the backend, now let's write our angular code and add some views. 221 | 222 | Open `app_name -> public -> index.html` and copy over this code: 223 | 224 | ```html 225 | 226 | 227 | 228 | 229 | Passport Angular 230 | 231 | 232 | 233 | 234 | 245 |
246 |
247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | ``` 259 | 260 | Great, now let's create out views. Copy the following code into each respective view template: 261 | 262 | # Home 263 | 264 | ```html 265 |

Home

266 | ``` 267 | 268 | # Signup 269 | 270 | ```html 271 |

Sign Up

272 | 273 |

274 |
275 |
276 |
277 | 278 |

279 | ``` 280 | 281 | # Login 282 | 283 | ```html 284 |

Login

285 | 286 |

287 |
288 |
289 | 290 |

291 | ``` 292 | 293 | # Profile 294 | 295 | ```html 296 |

Profile

297 | 298 |

User: {{ currentUser.username }}

299 | ``` 300 | 301 | Alright we're almost there! Let's add our main angular logic to the `app.js` file inside of the `js` directory: 302 | 303 | ```js 304 | var app = angular.module("PassportApp", ["ngRoute"]); 305 | 306 | app.config(function($routeProvider) { 307 | $routeProvider 308 | .when('/home', { 309 | templateUrl: 'views/home.html' 310 | }) 311 | .when('/login', { 312 | templateUrl: 'views/login.html', 313 | controller: 'LoginCtrl' 314 | }) 315 | .when('/signup', { 316 | templateUrl: 'views/signup.html', 317 | controller: 'SignUpCtrl' 318 | }) 319 | .when('/profile', { 320 | templateUrl: 'views/profile.html', 321 | resolve: { 322 | logincheck: checkLoggedin 323 | } 324 | }) 325 | .otherwise({ 326 | redirectTo: '/home' 327 | }) 328 | }); 329 | 330 | var checkLoggedin = function($q, $timeout, $http, $location, $rootScope) { 331 | var deferred = $q.defer(); 332 | 333 | $http.get('/loggedin').success(function(user) { 334 | $rootScope.errorMessage = null; 335 | //User is Authenticated 336 | if (user !== '0') { 337 | $rootScope.currentUser = user; 338 | deferred.resolve(); 339 | } else { //User is not Authenticated 340 | $rootScope.errorMessage = 'You need to log in.'; 341 | deferred.reject(); 342 | $location.url('/login'); 343 | } 344 | }); 345 | return deferred.promise; 346 | } 347 | ``` 348 | 349 | And finally, put the following code into the `controllers.js` file, also living inside of the `js` folder: 350 | 351 | ```js 352 | app.controller("NavCtrl", function($rootScope, $scope, $http, $location) { 353 | $scope.logout = function() { 354 | $http.post("/logout") 355 | .success(function() { 356 | $rootScope.currentUser = null; 357 | $location.url("/home"); 358 | }); 359 | } 360 | }); 361 | 362 | app.controller("SignUpCtrl", function($scope, $http, $rootScope, $location) { 363 | $scope.signup = function(user) { 364 | 365 | if (user.password == user.password2) { 366 | $http.post('/signup', user) 367 | .success(function(user) { 368 | $rootScope.currentUser = user; 369 | $location.url("/profile"); 370 | }); 371 | } 372 | } 373 | }); 374 | 375 | app.controller("LoginCtrl", function($location, $scope, $http, $rootScope) { 376 | $scope.login = function(user) { 377 | $http.post('/login', user) 378 | .success(function(response) { 379 | $rootScope.currentUser = response; 380 | $location.url("/profile"); 381 | }); 382 | } 383 | }); 384 | ``` 385 | 386 | That's it! Now fire up your server and give it a try, you should now have a working local authentication stratey in place. Don't forget to run `mongod` in a separate tab before starting your server. 387 | 388 | # [Facebook strategy tutorial](./facebook.md) 389 | 390 | ------------------------- 391 | ## Sources 392 | 393 | - [Express and Passport - Scotch.io](https://scotch.io/tutorials/easy-node-authentication-setup-and-local) 394 | - [Angular, Express and Passport - YouTube tutorial](https://www.youtube.com/watch?v=jtaSRzP0i30&feature=youtu.be) 395 | - [Source code from tutorial above](https://github.com/soaresdiogo/authenticatePassport) 396 | 397 | -------------------------- 398 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | //Express 2 | var express = require('express'); 3 | var app = express(); 4 | app.use(express.static(__dirname + '/public')); 5 | 6 | //Passport 7 | var passport = require('passport'); 8 | require('./config/passport')(passport); // pass passport for configuration 9 | 10 | //Cookie and session 11 | var cookieParser = require('cookie-parser'); 12 | var session = require('express-session'); 13 | app.use(session({ 14 | secret: 'this is the secret' 15 | })); 16 | app.use(cookieParser()); 17 | app.use(passport.initialize()); 18 | app.use(passport.session()); 19 | 20 | //Body-parser 21 | var bodyParser = require('body-parser'); 22 | app.use(bodyParser.json()); //for parsing application/json 23 | app.use(bodyParser.urlencoded({ 24 | extended: true 25 | })); 26 | 27 | //Load .env file 28 | var dotenv = require('dotenv'); 29 | dotenv.load(); 30 | 31 | // routes ====================================================================== 32 | require('./routes/auth.js')(app, passport); // load our routes and pass in our app and fully configured passport 33 | 34 | 35 | app.listen(3000); -------------------------------------------------------------------------------- /config/oauth.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | facebookAuth: { 3 | clientID: process.env.FB_CLIENT_ID, 4 | clientSecret: process.env.FB_SECRET, 5 | callbackURL: process.env.FB_CALLBACK_URL, 6 | enableProof: false 7 | } 8 | } -------------------------------------------------------------------------------- /config/passport.js: -------------------------------------------------------------------------------- 1 | // load all the things we need 2 | var LocalStrategy = require('passport-local').Strategy; 3 | var FacebookStrategy = require('passport-facebook').Strategy; 4 | var configAuth = require('./oauth'); 5 | // load up the user model 6 | var User = require('../models/user'); 7 | 8 | // expose this function to our app using module.exports 9 | module.exports = function(passport) { 10 | 11 | passport.serializeUser(function(user, done) { 12 | done(null, user); 13 | }); 14 | 15 | passport.deserializeUser(function(user, done) { 16 | done(null, user); 17 | }); 18 | 19 | passport.use('local-login', new LocalStrategy( 20 | function(username, password, done) { 21 | User.findOne({ 22 | username: username.toLowerCase() 23 | }, function(err, user) { 24 | // if there are any errors, return the error before anything else 25 | if (err) 26 | return done(err); 27 | 28 | // if no user is found, return the message 29 | if (!user) 30 | return done(null, false); 31 | 32 | // if the user is found but the password is wrong 33 | if (!user.validPassword(password)) 34 | return done(null, false); 35 | 36 | // all is well, return successful user 37 | return done(null, user); 38 | }); 39 | } 40 | )); 41 | 42 | // Facebook strategy 43 | passport.use(new FacebookStrategy({ 44 | 45 | // pull in our app id and secret from our auth.js file 46 | clientID : configAuth.facebookAuth.clientID, 47 | clientSecret : configAuth.facebookAuth.clientSecret, 48 | callbackURL : configAuth.facebookAuth.callbackURL 49 | 50 | }, 51 | 52 | // facebook will send back the token and profile 53 | function(token, refreshToken, profile, done) { 54 | // asynchronous 55 | process.nextTick(function() { 56 | 57 | // find the user in the database based on their facebook id 58 | User.findOne({ 'facebook.id' : profile.id }, function(err, user) { 59 | 60 | // if there is an error, stop everything and return that 61 | // ie an error connecting to the database 62 | if (err) 63 | return done(err); 64 | 65 | // if the user is found, then log them in 66 | if (user) { 67 | return done(null, user); // user found, return that user 68 | } else { 69 | // if there is no user found with that facebook id, create them 70 | var newUser = new User(); 71 | 72 | // set all of the facebook information in our user model 73 | newUser.facebook.id = profile.id; // set the users facebook id 74 | newUser.facebook.token = token; // we will save the token that facebook provides to the user 75 | newUser.facebook.name = profile.displayName; // look at the passport user profile to see how names are returned 76 | 77 | // save our user to the database 78 | newUser.save(function(err) { 79 | if (err) 80 | throw err; 81 | 82 | // if successful, return the new user 83 | return done(null, newUser); 84 | }); 85 | } 86 | 87 | }); 88 | }); 89 | 90 | })); 91 | }; 92 | -------------------------------------------------------------------------------- /facebook.md: -------------------------------------------------------------------------------- 1 | # Add facebook auth to your app with passport 2 | 3 | First thing we'll want to do is add a few more dependencies to our `package.json` 4 | 5 | ``` 6 | "dotenv": "^1.2.0", 7 | "passport-facebook": "^2.0.0" 8 | ``` 9 | 10 | Be sure to run `npm install` 11 | 12 | We'll use `passport-facebook` for our passport strategy configuration and `dotenv` to hide our API's secret key and client ID. 13 | 14 | Now open up your backend's `app.js` file from your app's root directory and add the following after your `body-parser` code: 15 | 16 | ```js 17 | //Load .env file 18 | var dotenv = require('dotenv'); 19 | dotenv.load(); 20 | ``` 21 | 22 | Now visit the [Facebook developer's portal](https://developers.facebook.com/) and where it says `My Apps` select `Add a New App` from the dropdown. Select `WWW` from the app options, enter a name for your app, click through and enter a category, click through again, scroll down to app configuration and enter your site url `http://localhost:3000/auth/facebook/callback`. 23 | 24 | Scroll to the bottom and select `skip to the developer dashboard`, this is where you'll get access to your Client ID and Secret Key. 25 | 26 | Take that information and enter it into a `.env` file inside of your app's root directory. (First be sure to add `.env` to your `.gitignore` file) 27 | 28 | ``` 29 | FB_CLIENT_ID=123456789 30 | FB_SECRET=a1b2c3d4e5f6g7h8j9k0 31 | FB_CALLBACK_URL=http://localhost:3000/auth/facebook/callback 32 | ``` 33 | 34 | Replace everything after the `=` signs with your information, the FB_CALLBACK_URL should remain the same. 35 | 36 | _Note: This should work fine, but if your app still won't recognize the ENV variables, try exporting them manually from the command line, e.g., open up your terminal and type: `export FB_CLIENT_ID=123456789` and do the same for your FB_SECRET and FB_CALLBACK_URL_ 37 | 38 | Now let's configure oath, create a file called `oath.js` inside of your `config` directory that lives inside of app's root directory. Add the following: 39 | 40 | ```js 41 | module.exports = { 42 | facebookAuth: { 43 | clientID: process.env.FB_CLIENT_ID, 44 | clientSecret: process.env.FB_SECRET, 45 | callbackURL: process.env.FB_CALLBACK_URL, 46 | enableProof: false 47 | } 48 | } 49 | ``` 50 | 51 | Now we can modify our passport configuration file to add the facebook strategy. 52 | Open `app_name -> config -> passport.js` and add the following below where you require local-strategy: 53 | 54 | ```js 55 | var FacebookStrategy = require('passport-facebook').Strategy; 56 | var configAuth = require('./oauth'); 57 | ``` 58 | 59 | Now add this to the bottom of your app before the closing `}` bracket from the `module.exports = function(passport) {`: 60 | 61 | ```js 62 | // Facebook strategy 63 | passport.use(new FacebookStrategy({ 64 | 65 | // pull in our app id and secret from our auth.js file 66 | clientID : configAuth.facebookAuth.clientID, 67 | clientSecret : configAuth.facebookAuth.clientSecret, 68 | callbackURL : configAuth.facebookAuth.callbackURL 69 | 70 | }, 71 | 72 | // facebook will send back the token and profile 73 | function(token, refreshToken, profile, done) { 74 | // asynchronous 75 | process.nextTick(function() { 76 | 77 | // find the user in the database based on their facebook id 78 | User.findOne({ 'facebook.id' : profile.id }, function(err, user) { 79 | 80 | // if there is an error, stop everything and return that 81 | // ie an error connecting to the database 82 | if (err) 83 | return done(err); 84 | 85 | // if the user is found, then log them in 86 | if (user) { 87 | return done(null, user); // user found, return that user 88 | } else { 89 | // if there is no user found with that facebook id, create them 90 | var newUser = new User(); 91 | 92 | // set all of the facebook information in our user model 93 | newUser.facebook.id = profile.id; // set the users facebook id 94 | newUser.facebook.token = token; // we will save the token that facebook provides to the user 95 | newUser.facebook.name = profile.displayName; // look at the passport user profile to see how names are returned 96 | 97 | // save our user to the database 98 | newUser.save(function(err) { 99 | if (err) 100 | throw err; 101 | 102 | // if successful, return the new user 103 | return done(null, newUser); 104 | }); 105 | } 106 | 107 | }); 108 | }); 109 | 110 | })); 111 | ``` 112 | 113 | Okay, the facebook-strategy is in place, but we need to update our user model to reflect the code in our passport configuration. Open up `app_name -> models -> user.js` and replace your user schema with: 114 | 115 | ```js 116 | // define the schema for our user model 117 | var userSchema = mongoose.Schema({ 118 | username: String, 119 | password: String, 120 | email: String, 121 | firstName: String, 122 | lastName: String, 123 | facebook: { 124 | id: String, 125 | token: String, 126 | name: String 127 | } 128 | }); 129 | ``` 130 | 131 | We're almost done, now let's go add the backend routes that allow us to grant access from facebook and redirect to our app. Open up `app_name -> routes -> auth.js` and add the following code before the closing `};` bracket from `module.exports = function(app, passport) {`: 132 | 133 | ```js 134 | 135 | // Facebook auth routes 136 | app.get('/auth/facebook', function authenticateFacebook (req, res, next) { 137 | req.session.returnTo = '/#' + req.query.returnTo; 138 | next (); 139 | }, 140 | passport.authenticate ('facebook')); 141 | 142 | app.get('/auth/facebook/callback', function (req, res, next) { 143 | var authenticator = passport.authenticate ('facebook', { 144 | successRedirect: req.session.returnTo, 145 | failureRedirect: '/' 146 | }); 147 | 148 | delete req.session.returnTo; 149 | authenticator (req, res, next); 150 | }) 151 | ``` 152 | 153 | Let's add a facebook login button to both our `login` and `signup` pages (inside of `app_name -> public -> views`: 154 | 155 | ```html 156 |

Login or Register with:

157 | 158 | Facebook 159 | ``` 160 | 161 | You can see how the query string from the end of the anchor tag's href will allow us to redirect to a route being used by the angular router, thus bridging us from the backend routing to the front end. 162 | 163 | One last thing, let's make sure the `profile` page will display the user's name when they log in with facebook. 164 | 165 | Open up `app_name -> public -> views -> profile.html` and replace the code there with: 166 | 167 | ```html 168 |

Profile

169 | 170 |

User: {{ currentUser.username || currentUser.facebook.name }}

171 | ``` 172 | 173 | All done! Bear in mind this is a very basic implementation, if you're going to use this in production you'll want to add some error handling. 174 | 175 | ------------------------- 176 | ## Sources 177 | 178 | - [Passport-facebook - Scotch.io](https://scotch.io/tutorials/easy-node-authentication-facebook) 179 | - [Redirection issue](https://github.com/jaredhanson/passport-facebook/issues/106) 180 | 181 | -------------------------- 182 | 183 | Shout out to Tim Garcia and Elie Schoppik for helping out! 184 | 185 | -------------------------------------------------------------------------------- /models/index.js: -------------------------------------------------------------------------------- 1 | var mongoose = require("mongoose"); 2 | mongoose.connect("mongodb://localhost/passport-db"); 3 | 4 | mongoose.set("debug", true); 5 | 6 | module.exports.User = require("./user"); -------------------------------------------------------------------------------- /models/user.js: -------------------------------------------------------------------------------- 1 | // load the things we need 2 | var mongoose = require('mongoose'); 3 | var bcrypt = require('bcrypt-nodejs'); 4 | 5 | // define the schema for our user model 6 | var userSchema = mongoose.Schema({ 7 | username: String, 8 | password: String, 9 | email: String, 10 | firstName: String, 11 | lastName: String, 12 | facebook: { 13 | id: String, 14 | token: String, 15 | name: String 16 | } 17 | }); 18 | 19 | // methods ====================== 20 | // generating a hash 21 | userSchema.methods.generateHash = function(password) { 22 | return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null); 23 | }; 24 | 25 | // checking if password is valid 26 | userSchema.methods.validPassword = function(password) { 27 | return bcrypt.compareSync(password, this.password); 28 | }; 29 | 30 | // create the model for users and expose it to our app 31 | module.exports = mongoose.model('User', userSchema); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "passport-angular", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "bcrypt-nodejs": "0.0.3", 14 | "body-parser": "^1.14.2", 15 | "cookie-parser": "^1.4.0", 16 | "dotenv": "^1.2.0", 17 | "express": "^4.13.3", 18 | "express-session": "^1.12.1", 19 | "mongoose": "^4.3.4", 20 | "morgan": "^1.6.1", 21 | "passport": "^0.3.2", 22 | "passport-facebook": "^2.0.0", 23 | "passport-local": "^1.0.0" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Passport Angular 6 | 7 | 8 | 9 | 10 | 11 | 12 | 23 |
24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /public/js/app.js: -------------------------------------------------------------------------------- 1 | var app = angular.module("PassportApp", ["ngRoute"]); 2 | 3 | app.config(function($routeProvider) { 4 | $routeProvider 5 | .when('/home', { 6 | templateUrl: 'views/home.html' 7 | }) 8 | .when('/login', { 9 | templateUrl: 'views/login.html', 10 | controller: 'LoginCtrl' 11 | }) 12 | .when('/signup', { 13 | templateUrl: 'views/signup.html', 14 | controller: 'SignUpCtrl' 15 | }) 16 | .when('/profile', { 17 | templateUrl: 'views/profile.html', 18 | resolve: { 19 | logincheck: checkLoggedin 20 | } 21 | }) 22 | .otherwise({ 23 | redirectTo: '/home' 24 | }) 25 | }); 26 | 27 | var checkLoggedin = function($q, $timeout, $http, $location, $rootScope) { 28 | var deferred = $q.defer(); 29 | 30 | $http.get('/loggedin').success(function(user) { 31 | $rootScope.errorMessage = null; 32 | //User is Authenticated 33 | if (user !== '0') { 34 | $rootScope.currentUser = user; 35 | deferred.resolve(); 36 | } else { //User is not Authenticated 37 | $rootScope.errorMessage = 'You need to log in.'; 38 | deferred.reject(); 39 | $location.url('/login'); 40 | } 41 | }); 42 | return deferred.promise; 43 | } -------------------------------------------------------------------------------- /public/js/controllers.js: -------------------------------------------------------------------------------- 1 | app.controller("NavCtrl", function($rootScope, $scope, $http, $location) { 2 | $scope.logout = function() { 3 | $http.post("/logout") 4 | .success(function() { 5 | $rootScope.currentUser = null; 6 | $location.url("/home"); 7 | }); 8 | } 9 | }); 10 | 11 | app.controller("SignUpCtrl", function($scope, $http, $rootScope, $location) { 12 | $scope.signup = function(user) { 13 | 14 | // TODO: verify passwords are the same and notify user 15 | if (user.password == user.password2) { 16 | $http.post('/signup', user) 17 | .success(function(user) { 18 | $rootScope.currentUser = user; 19 | $location.url("/profile"); 20 | }); 21 | } 22 | } 23 | }); 24 | 25 | app.controller("LoginCtrl", function($location, $scope, $http, $rootScope) { 26 | $scope.login = function(user) { 27 | $http.post('/login', user) 28 | .success(function(response) { 29 | $rootScope.currentUser = response; 30 | $location.url("/profile"); 31 | }); 32 | } 33 | }); -------------------------------------------------------------------------------- /public/views/home.html: -------------------------------------------------------------------------------- 1 |

Home

-------------------------------------------------------------------------------- /public/views/login.html: -------------------------------------------------------------------------------- 1 |

Login

2 | 3 |

4 |
5 |
6 | 7 |

8 | 9 |

Login or Register with:

10 | 11 | Facebook -------------------------------------------------------------------------------- /public/views/profile.html: -------------------------------------------------------------------------------- 1 |

Profile

2 | 3 |

User: {{ currentUser.username || currentUser.facebook.name }}

-------------------------------------------------------------------------------- /public/views/signup.html: -------------------------------------------------------------------------------- 1 |

Sign Up

2 | 3 |

4 |
5 |
6 |
7 | 8 |

9 | 10 |

Sign Up or Register with:

11 | 12 | Facebook -------------------------------------------------------------------------------- /routes/auth.js: -------------------------------------------------------------------------------- 1 | var db = require("../models"); 2 | 3 | module.exports = function(app, passport) { 4 | // process the login form 5 | app.post("/login", passport.authenticate('local-login'), function(req, res) { 6 | res.json(req.user); 7 | }); 8 | 9 | // handle logout 10 | app.post("/logout", function(req, res) { 11 | req.logOut(); 12 | res.send(200); 13 | }) 14 | 15 | // loggedin 16 | app.get("/loggedin", function(req, res) { 17 | res.send(req.isAuthenticated() ? req.user : '0'); 18 | }); 19 | 20 | // signup 21 | app.post("/signup", function(req, res) { 22 | db.User.findOne({ 23 | username: req.body.username 24 | }, function(err, user) { 25 | if (user) { 26 | res.json(null); 27 | return; 28 | } else { 29 | var newUser = new db.User(); 30 | newUser.username = req.body.username.toLowerCase(); 31 | newUser.password = newUser.generateHash(req.body.password); 32 | newUser.save(function(err, user) { 33 | req.login(user, function(err) { 34 | if (err) { 35 | return next(err); 36 | } 37 | res.json(user); 38 | }); 39 | }); 40 | } 41 | }); 42 | }); 43 | 44 | // Facebook auth routes 45 | app.get('/auth/facebook', function authenticateFacebook (req, res, next) { 46 | req.session.returnTo = '/#' + req.query.returnTo; 47 | next (); 48 | }, 49 | passport.authenticate ('facebook')); 50 | 51 | app.get('/auth/facebook/callback', function (req, res, next) { 52 | var authenticator = passport.authenticate ('facebook', { 53 | successRedirect: req.session.returnTo, 54 | failureRedirect: '/' 55 | }); 56 | 57 | delete req.session.returnTo; 58 | authenticator (req, res, next); 59 | }) 60 | }; -------------------------------------------------------------------------------- /sample.env: -------------------------------------------------------------------------------- 1 | FB_CLIENT_ID=123456789 2 | FB_SECRET=a1b2c3d4e5f6g7h8j9k0 3 | FB_CALLBACK_URL=http://localhost:3000/auth/facebook/callback --------------------------------------------------------------------------------