I'm using Express 4.2.0 with passport 0.2.0.
The express-session middleware that I am using is 1.2.1
I'm relatively new to node authentication so please bear with me.
I noticed that for everyone page load, passport is executing a db request:
Executing (default): SELECT * FROM "users" WHERE "users"."user_id"=7 LIMIT 1;
This doesn't make sense to me as I would think that the user has already been authenticated and serialized. And the session is now stored in the browser cookie. I also checked that I do have a cookie session stored in my browser.
Here are my app.js configuration:
var express = require('express');
var path = require('path');
var favicon = require('static-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
//var sys = require('sys');
var cons = require('consolidate');
/* sequelize */
var db = require('./models');
/* passport and its friends */
var passport = require('passport');
var flash = require('connect-flash');
var session = require('express-session');
/* routes */
var routes = require('./routes/index');
var users = require('./routes/users');
//filesystem middleware
//var fs = require('fs');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.engine('dust', cons.dust);
app.set('view engine', 'dust');
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser('hashionhashion'));
app.use(require('less-middleware')(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({ secret: 'hashionhashion' })); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
//routing
app.use('/', routes);
app.use('/users', users);
and here is the passport serialize/deserialize function:
passport.serializeUser(function(user, done) {
done(null, user.user_id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
db.User.find({ where: {user_id: id} }).success(function(user){
done(null, user);
}).error(function(err){
done(err, null);
});
});
Executing a query on each request to fetch the authenticated user data sometimes is not a good practice(but it is commonly used in apps).
In one of my apps, i only needed id of the authenticated user rather than all data (like password,last_login_date,register_date, ...) so i changed passport configs like below:
passport.serializeUser(function(user, done) {
done(null, {id: user.id});
});
// used to deserialize the user
passport.deserializeUser(function(object, done) {
done(null, object); // object is: {id: user_id}
});
and then in your controllers you can get user id from session:
router.get('/', function(req, res, next)=> {
const userId = req.user.id;
// now do a database query only if needed :)
});
you can also define a custom middleware to fetch user from db and set to
req.user to use in next middleware:
function fetchUser (req, res, next) {
db.User.find({ where: {id:req.user.id} }).success(function(user){
req.user = user;
next(); // will trigger next middleware
}).error(function(err){
next(err); // will trigger error handler
});
}
router.get('/', fetchUser, function(req, res, next)=> {
const user = req.user;
// now user is a object that is fetched from db and has all properties
});
In this approach you'll execute query for retrieving user from db only if it's needed and not for all routes.
Related
I want to have an online map which publicly loads and shows all my activities from my Strava account.
I have found a web app on GitHub which does what I want but the user has to log in with the Strava log in screen before he than can see his own activities: https://github.com/nsynes/ActivityMap
It seems it uses Passport Strava to authenticate with Strava: https://www.passportjs.org/packages/passport-strava-oauth2/
Is it possible to adjust the script so it always logs in automatically my account and than shows my activities publicly to everyone who visits the map?
The full script is here: https://github.com/nsynes/ActivityMap/blob/master/activity-map-app.js
My STRAVA_CLIENT_ID and STRAVA_CLIENT_SECRET are from my Strava account and saved in a .env file.
const express = require('express')
const passport = require('passport')
const util = require('util')
const StravaStrategy = require('passport-strava-oauth2').Strategy
const dotenv = require('dotenv');
const path = require('path');
const cookieParser = require('cookie-parser')
const bodyParser = require('body-parser');
const session = require('express-session');
var strava = require('strava-v3');
const decode = require('geojson-polyline').decode
const geodist = require('geodist');
dotenv.config();
const port = process.env.PORT || 3000
const app = express();
// configure Express
//app.use(express.logger());
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: false }));
//app.use(express.methodOverride());
app.use(session({
secret: 'monkey tennis',
resave: true,
saveUninitialized: true,
maxAge: 1800 * 1000
}));
app.use(passport.initialize());
app.use(passport.session());
app.use('/css', express.static(path.join(__dirname, 'css')));
app.use('/fontawesome', express.static(path.join(__dirname, 'fontawesome')));
app.use('/js', express.static(path.join(__dirname, 'js')));
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
// Passport session setup.
passport.serializeUser(function(user, done) { done(null, user) });
passport.deserializeUser(function(obj, done) {done(null, obj) });
passport.use(new StravaStrategy({
clientID: process.env.STRAVA_CLIENT_ID,
clientSecret: process.env.STRAVA_CLIENT_SECRET,
callbackURL: "/auth/strava/callback"
},
function(accessToken, refreshToken, profile, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
// To keep the example simple, the user's Strava profile is returned to
// represent the logged-in user. In a typical application, you would want
// to associate the Strava account with a user record in your database,
// and return that user instead.
return done(null, profile);
});
}
));
app.get('/', ensureAuthenticated, function(req, res){
pagePath = path.join(__dirname, '/index.html');
res.sendFile(pagePath);
});
app.get('/userPhoto', ensureAuthenticated, function(req, res){
if ( req.user ) {
res.json({ 'photo': req.user.photos[req.user.photos.length-1].value });
} else {
res.sendStatus(404);
}
});
// Use passport.authenticate() as route middleware to authenticate the
// request. Redirect user to strava, then strava will redirect user back to
// this application at /auth/strava/callback
app.get('/auth/strava',
passport.authenticate('strava', { scope: ['activity:read'], approval_prompt: ['force'] }),
function(req, res){
// The request will be redirected to Strava for authentication, so this
// function will not be called.
});
// GET /auth/strava/callback
// Use passport.authenticate() as route middleware to authenticate the
// request. If authentication fails, the user will be redirected back to the
// login page. Otherwise, the primary route function function will be called,
// which, in this example, will redirect the user to the home page.
app.get('/auth/strava/callback',
passport.authenticate('strava', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
app.get('/logout', function(req, res){
req.logout();
res.cookie("connect.sid", "", { expires: new Date() });
res.render('login', { user: req.user });
});
app.get('/login', function(req, res){
res.render('login', { user: req.user });
});
The issue here is when i log in with correct details, the session should be created and cookie should be generated at client side which is happening when i use postman but not in case of web browsers.
I am using the following:
passport for authenticating login details from mongoDB using mongoose
express-session for creating session when a user logs in.
cors at the backend (react is running at port 3000 and node is running at port 4000)
Here is my app.js (backend):
var createError = require('http-errors');
var cookieParser = require('cookie-parser')
var path = require('path');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var serverRouter = require("./routes/server");
var DbRouter = require("./routes/DbRequest");
var ProductRouter = require("./routes/ProductRouter");
var CategoryRouter = require("./routes/CategoryRouter");
const session = require("express-session");
const passport = require("./passport");
var cors = require("cors");
var express = require('express');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(cors());
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser());
// USING SESSION AND PASSPORT
app.use(session({
secret: 'adsdsacoasdqwdn',
resave: false,
saveUninitialized: false,
cookie: { secure: false }
}))
app.use(passport.initialize());
app.use(passport.session());
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use("/api/admin",serverRouter);
app.use("/api/user",DbRouter);
app.use("/api/product",ProductRouter);
app.use("/api/category",CategoryRouter);
app.use(express.json({ extended:false}));
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', "*");
res.header('Access-Control-Allow-Methods','GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
})
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
Here is my file where i am making the routes and creating sessions :
var express = require("express");
var router = express.Router();
var connectDB = require("./connect");
const passport = require("../passport");
connectDB();
router.post("/adminlogin", (req,res,next) => {
passport.authenticate("local-adminSignin",function(err,user,info){
if(err){
return res.status(500).send(err)
}
req.login(user,function(error){
if(error){
return res.status(500).json(err)
}
return res.json(user);
})
})(req,res,next);
})
router.get("/currentAdmin", (req,res,next) => {
res.json(req.user)
})
module.exports = router;
Here , when i make a get request to "/currentAdmin" after i logged in as admin, i should be getting the user object as a response which contains all details of the admin from mongoDB.
POSTMAN LOGIN (i cant post images because this is a new account, i've linked gyazo below) :
https://gyazo.com/5569415297fbe7c7178a93634d1506e6
AFTER LOGIN, MAKING REQUEST TO "/currentAdmin"
https://gyazo.com/cd2ec99e1ee8f959d0c3874b43b76454
But, when i make same request from react, it gives me empty object as a response. One thing i noticed here is cookies are generated in postman and i get response but no cookies are there in the browser after admin login.
MY PASSPORT INDEX.JS FILE
const passport = require("passport");
const User = require("../routes/AdminSchema")
passport.serializeUser(function(user, done) {
console.log('i am serializing the user');
done(null, user.username);
});
passport.deserializeUser(function(username, done) {
console.log('i am de-serializing the user');
User.findOne({username}).lean().exec((err,user) => {
done(err, user);
});
});
//import strategy
const AdminLoginStrategy = require("./AdminLoginStrategy");
passport.use('local-adminSignin',AdminLoginStrategy);
module.exports = passport;
MY LOGIN STRATEGY FILE:
const Strategy = require("passport-local").Strategy;
const User = require("../routes/AdminSchema")
const bcrypt = require("bcryptjs")
const LoginStrategy = new Strategy({passReqToCallback:true},function(req,username,password,done){
User.findOne({username}).lean().exec((err,user) => {
if(err){
return done("db error idk bro",null)
}
if(!user){
return done("user not found!",null)
}
const isPasswordValid = bcrypt.compareSync(password, user.password);
if(!isPasswordValid){
return done("username or password not valid!",null)
}
return done(null,user)
})
})
module.exports = LoginStrategy
PS: If i send text response or other json from "/currentAdmin", I am getting it in react but i am not getting the res.user object which i think is because of cookies not being generated in the browser.
How can i solve this issue? Thanks!
I've spent more time than I'd like to admit scouring countless posts online that have the same problem as me, to no avail. The majority of solutions seemed to be things like not including
passReqToCallback: true in my LocalStrategy.
passport.serializeUser() and passport.deserializeUser() in my init file.
app.use(passport.initialize()) and app.use(passport.session()) in app.js.
Requiring and using app.use(cookieParser()) in app.js.
Passing cookie parser my secret key.
Adding proxy and cookie attributes to my expressSession variable in app.js.
Invoking req.login inside passport.authenticate within my page route.
And several other little tweaks I can't remember...
My login.js is as follows;
var LocalStrategy = require('passport-local').Strategy;
var User = require('../../models/user');
var bCrypt = require('bcrypt-nodejs');
module.exports = function(passport) {
passport.use('login', new LocalStrategy({passReqToCallback: true},
function(req, username, password, done) {
//Queries MongoDB For User
User.findOne({'username': username}, function(err, user) {
//In The Event Of An Error, Throw It
if (err) {
return done(err);
}
//Username Does Not Exist, Log Error, Callback, Flash Error Message
if (!user){
console.log('User: '+ username + ", does not exist.");
return done(null, false, req.flash('message', 'User Not found.'));
}
//User Exists, But Password Is Incorrect
if (!isValidPassword(user, password)){
console.log('Invalid Password');
return done(null, false, req.flash('message', 'Invalid Password')); // redirect back to login page
}
//If No Previous Error Conditions Are Met - Username/Password Are Correct
console.log("Validated User: " + username + ".");
//req.user = user;
return done(null, user);
}); //End of User.findOne()
}) //End of new LocalStrategy
); //End of passport.use()
/*
var isValidPassword = function(user, password){
return bCrypt.compareSync(password, user.password);
}
*/
//Passwords are not currently hashed in my DB, so ignore bcrypt for now.
var isValidPassword = function(user, password) {
return user.password == password;
}
}
My passport-init.js file
var login = require('./login');
var User = require('../../models/user');
module.exports = function(passport){
//Serialise User
passport.serializeUser(function(user, done) {
console.log("Serializing User: " + user.username + "\n" + user + ".");
done(null, user._id);
});
//De-Serialise User
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
console.log("Deserializing User: " + user.username + "\n" + user);
done(err, user);
});
});
//Setting up Passport Strategy for Login
login(passport);
}
My index.js file contains the POST Login route
/* POST Login Page*/
router.post('/login', passport.authenticate('login', {
successRedirect: '/dashboard',
failureRedirect: '/login',
failureFlash: true
}));
And dashboard.js contains all the routing for /dashboard/other-pages.
These ones are protected by the isAuthenticated function.
var express = require('express');
var router = express.Router();
var database = require('../public/javascripts/db-connect.js');
var isAuthenticated = function(req, res, next) {
console.log("User: " + req.user);
console.log("Authenticated?: " + req.isAuthenticated());
if (req.isAuthenticated()) {
return next();
} else {
res.redirect('/unauthorised');
}
}
module.exports = function(passport) {
//Routes /dashboard --> dashboard.pug
router.get('/', isAuthenticated, function(req, res, next) {
database.getData("busdata", function(err, data) {
if (err) {
console.error(err);
} else {
res.render('dashboard', {title: 'Dashboard', busdata: data});
}
});
});
//Routes /dashboard/journeys --> journeys.pug
router.get('/journeys', isAuthenticated, function(req, res, next) {
database.getData("journeydata", function(err, data) {
if (err) {
console.error(err);
} else {
res.render('journeys', {title: 'Journey Graphs', journeydata: data});
}
});
});
return router;
}
So when I run the app;
I check localhost:3000/dashboard and localhost:3000/dashboard/journeys. They correctly re-direct me to /unauthorised.
Navigate to /login.
Enter a correct username and password, the console then spits out:
Validated User: TomPlum. Meaning passport.use() reached return done(null, user)
Serialising User: TomPlum + the objects properties
POST /login 302 time ms
User: undefined from isAuthenticated
isAuthenticated? false
GET /dashboard 302 time ms
Deserialising User: TomPlum + the objects properties
I'm then redirected to /unauthorised as isAuthenticated() evaluates to false.
Why is req.user undefined? Should I be using a LocalStrategy if my MongoDB is not-local? (Amazon Atlas Server). Other forum posts have suggested it could be a cookie issue but I've included the relevant cookie-parser includes in my app.js file.
app.js is here in-case it's an order issue.
//Require Variables
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
//Mongo DB Connection Settings
var dbConfig = require('./db'); //db.js contains DB URL
var mongoose = require('mongoose');
mongoose.connect(dbConfig.url); //dbConfig.url refers to the export in db.js
//Page Routing
//var index = require('./routes');
var users = require('./routes/users');
var dashboard = require('./routes/dashboard')(passport);
var app = express();
app.d3 = require('d3');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public/images', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser('urban_sensing'));
app.use(express.static(path.join(__dirname, 'public')));
//app.use('/', index);
app.use('/dashboard', dashboard);
app.use('/users', users);
//Configuring Passport
var passport = require('passport');
var expressSession = require('express-session');
app.enable('trust-proxy');
app.use(expressSession({
secret: 'urban_sensing',
resave: true,
saveUninitialized: true,
proxy: true,
cookie: {
secure: true,
maxAge: 3600000
}
}));
app.use(passport.initialize());
app.use(passport.session());
//Flash Messaging For Passport
var flash = require('connect-flash');
app.use(flash());
//Initialize Passport
var initPassport = require('./public/javascripts/passport-init');
initPassport(passport);
var index = require('./routes/index')(passport);
app.use('/', index);
//Catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
//Error Handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
Some of the app.use(expressSession({..})); properties may currently be unnecessary as they've been added in an attempt to fix the issue.
Any help would be appreciated.
After too much time on this, turns out it was simply the order of app.js.
By moving
var dashboard = require('./routes/dashboard')(passport);
app.use('/dashboard', dashboard);
below all the passport configuration. It now works correctly. It seems that something wasn't initialised correctly during the routing of /dashboard when it was before the passport code.
Updated app.js
//Require Variables
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
//Mongo DB Connection Settings
var dbConfig = require('./db'); //db.js contains DB URL
var mongoose = require('mongoose');
mongoose.connect(dbConfig.url); //dbConfig.url refers to the export in db.js
//Page Routing
//var index = require('./routes');
var users = require('./routes/users');
var app = express();
app.d3 = require('d3');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public/images', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser('urban_sensing'));
app.use(express.static(path.join(__dirname, 'public')));
//app.use('/', index);
app.use('/users', users);
//Configuring Passport
var passport = require('passport');
var expressSession = require('express-session');
app.use(expressSession({
secret: 'urban_sensing',
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 3600000 //1 Hour
}
}));
app.use(passport.initialize());
app.use(passport.session());
//Flash Messaging For Passport
var flash = require('connect-flash');
app.use(flash());
//Initialize Passport
var initPassport = require('./public/javascripts/passport-init');
initPassport(passport);
var dashboard = require('./routes/dashboard')(passport);
app.use('/dashboard', dashboard);
var index = require('./routes/index')(passport);
app.use('/', index);
//Catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
//Error Handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
So i managed to get passport-twitter working together with jsonwebtoken library, but in order for it to work properly I have to use express-session as the middleware. I don't want to add session because I'm using jsonwebtoken to return the token.
Here's the code
autheticate.js
router.get('/twitter', function(req, res, next){
passport.authenticate('twitter', {session: false}, function(err, user, info){
if(err){ return next(err); }
if(user){
var token = createToken(user);
console.log(token);
return res.json({token: token});
} else {
return res.status(401).json(info);
}
})(req, res, next);
});
I already added session: false as the argument, but on server.js it keeps spitting error, that i need to use express-session.
server.js
var express = require('express');
var path = require('path');
var logger = require('morgan');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var passport = require('passport');
var session = require('express-session');
var config = require('./config');
mongoose.connect('mongodb://localhost', function() {
console.log("Connected to the database");
})
require('./passport')(passport);
var app = express();
var authenticate = require('./routes/authenticate')(app, express, passport);
var api = require('./routes/api') (app, express, passport);
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(session({
secret: config.TOKEN_SECRET,
resave: true,
saveUninitialized: true,
}));
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use('/auth', authenticate);
app.use('/api', api);
app.get('*', function(req, res) {
res.sendFile(__dirname + '/public/app/views/index.html');
});
app.listen(3000, function(err) {
if(err) {
return res.send(err);
}
console.log("Listening on port 3000");
});
So whenever i delete app.use(session()) and try to authenticate with passport-twitter. I will get this error
error Oauth Strategy requires app.use(express-session));
I know that the obvious solution is to add that line, but I dont want to use session. Does Oauth 0.1 really need to use session?
Passports OAuth based strategies use the session middleware to keep track of the login process. You do not need to use the session middleware for anything else, just base your authentication on your token and ignore the session.
I'm working on developing a node.js (using node.js v0.10.26) express web application using Google's oauth 2.0 with passport.js. Up to now it's worked fine, as the route definitions were contained within the app.js file. However, now that I'm breaking up the route logic into separate modules, I'm running into problems. My file structure is broken up like this:
authentication
├── cert.pem
└── key.pem
bin
└── www
data
└── (mongo database files)
node_modules
└── (node module files for: body-parser, cookie-parser,
debug, express, express-session, jade, method-override,
mongodb, mongoose, morgan, passport, passport-google, static-favicon)
routes
├── account.js
├── index.js
└── login.js
views
├── account.jade
├── index.jade
├── layout.jade
└── login.jade
app.js
oauth.js
package.json
The .pem files are for the ssl key and certificate. www is a script which establishes an https server:
var debug = require('debug')('kaiwaquiz');
var fs = require('fs');
var http = require('http');
var https = require('https');
var app = require('../app');
var options = {
key: fs.readFileSync('./authentication/key.pem'),
cert: fs.readFileSync('./authentication/cert.pem')
};
var port = process.env.PORT || 3000;
var server = https.createServer(options, app).listen(port, function(){
debug('Express server listening on port ' + server.address().port);
});
It calls uses app.js (note the comment above the /login route):
//Express Dependencies
var express = require('express');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var logger = require('morgan');
var session = require('express-session');
var methodOverride = require('method-override');
var favIcon = require('static-favicon');
//Passport Dependencies
var config = require('./oauth.js');
var passport = require('passport');
var GoogleStrategy= require('passport-google').Strategy;
//Mongo Dependencies
var mongodb = require('mongodb');
var mongoose = require('mongoose');
//Server Variables
var app = express();
var indexRoutes = require('./routes/index');
var loginRoutes = require('./routes/login');
var accountRoutes = require('./routes/account');
//Serialize and Deserialize
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done){
done(null, obj);
});
//Passport Configuration
passport.use(new GoogleStrategy({
clientID: config.google.clientID,
clientSecret: config.google.clientSecret,
returnURL: config.google.returnURL,
realm: config.google.realm
},
function(accessToken, refreshToken, profile, done){
process.nextTick(function(){
app.locals.currentUserName = refreshToken.displayName;
return done(null, profile);
});
}
));
//Configure View Engine
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
//Process Static Content
app.use(favIcon());
app.use(express.static(__dirname + '/public'));
//Process Dynamic Content
app.use(cookieParser());
app.use(bodyParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(methodOverride());
app.use(session({secret: 'its_a_secret'}));
app.use(passport.initialize());
app.use(passport.session());
//Log results
app.use(logger('dev'));
function ensureAuthenticated(req, res, next) {
if(req.isAuthenticated()) {return next();}
res.redirect('/login');
}
//Application Routes
///THE FOLLOWING WORKS FINE///
app.get('/', indexRoutes);
///THE FOLLOWING /LOGIN ROUTE FAILS UNLESS THE loginRoutes MODULE IS REPLACED BY function(req, res){ res.render('login'); }///
app.get('/login', loginRoutes);
app.get('/account', ensureAuthenticated, accountRoutes);
app.get('/auth/google', passport.authenticate('google'), function(req, res){});
app.get('/auth/google/callback', passport.authenticate('google', {failureRedirect: '/'}),
function(req, res){
res.redirect('/account');
}
);
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
module.exports = app;
The index route works fine, and uses index.js:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
res.render('index');
});
module.exports = router;
The login route fails, even though login.js employs the same format:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
res.render('login');
});
module.exports = router;
It still fails, even if I use index.js, and only works if I put the res.render() function directly in the code like this:
app.get('/login', function(req, res){
res.render('login');
});
The oauth.js file just contains the client information for connecting using google.com
Does anyone have any ideas as to why this problem is occuring?
Edit:
If I change the /login route, the /account route breaks in the same way that /login did. So, this app.js works fine:
//Express Dependencies
var express = require('express');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var logger = require('morgan');
var session = require('express-session');
var methodOverride = require('method-override');
var favIcon = require('static-favicon');
//Passport Dependencies
var config = require('./oauth.js');
var passport = require('passport');
var GoogleStrategy= require('passport-google').Strategy;
//Mongo Dependencies
var mongodb = require('mongodb');
var mongoose = require('mongoose');
//Server Variables
var app = express();
var indexRoutes = require('./routes/index');
var loginRoutes = require('./routes/login');
var accountRoutes = require('./routes/account');
//Serialize and Deserialize
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done){
done(null, obj);
});
//Passport Configuration
passport.use(new GoogleStrategy({
clientID: config.google.clientID,
clientSecret: config.google.clientSecret,
returnURL: config.google.returnURL,
realm: config.google.realm
},
function(accessToken, refreshToken, profile, done){
process.nextTick(function(){
app.locals.currentUserName = refreshToken.displayName;
return done(null, profile);
});
}
));
//Configure View Engine
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
//Return Static Content
app.use(favIcon());
app.use(express.static(__dirname + '/public'));
//Return Dynamic Content
app.use(cookieParser());
app.use(bodyParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(methodOverride());
app.use(session({secret: 'its_a_secret'}));
app.use(passport.initialize());
app.use(passport.session());
//Log results
app.use(logger('dev'));
function ensureAuthenticated(req, res, next) {
if(req.isAuthenticated()) {return next();}
res.redirect('/login');
}
//Application Routes
app.get('/login', function(req, res){
res.render('login');
});
app.get('/account', ensureAuthenticated, function(req, res){
res.render('account', {user: req.app.locals.currentUserName});
});
app.get('/', function(req, res){
res.render('index');
});
app.get('/auth/google', passport.authenticate('google'), function(req, res){});
app.get('/auth/google/callback', passport.authenticate('google', {failureRedirect: '/'}),
function(req, res){
res.redirect('/account');
}
);
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
module.exports = app;
According to the Router documentation, I think you need to do
app.use('/login', loginRoutes);
instead of
app.get('/login', loginRoutes);
Same goes for your index and other routes that are using express.Router().
try the following as login.js:
var express = require('express');
var router = express.Router();
/* GET login page. */
router.get('/login', function(req, res) {
res.render('login');
});
module.exports = router;
The documentation says:
// will handle any request that ends in /events
// depends on where the router is "use()'d"
router.get('/events', function(req, res, next) {
// ..
});
Through some trial and error, I've been able to determine that external routing modules must be use()'d, instead of get()'d, like mscdex indicated. However, the end routes must use an http verb like get(), post(), etc... The /account route, which currently uses a get(), contains two methods, the ensureAuthenticated(), and inline rendering method. This is because the http verb methods can contain more than one method to be executed, as opposed to the use(). For the future, it seems better to do the authentication within the routing modules themselves, as the method to do so is added to the request variable. Thanks for the assistance!