[FIXED]:
in my code, i was missing
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
i am writing an demo app to access microsoft one-drive
when i visit http://localhost:3000/auth/mslive, my app will redirect me to single-sign-on with windows-live
however, callback function in "/mslive" and "/mslive/callback" never get hit.
and I keep getting 500 error when windows live try to re-direct back to my app.
any idea?
Remote Address:127.0.0.1:3000
Request URL:http://anotherdemoapp.localtest.me:3000/auth/mslive/callback?code=d3f9d642-b013-af4e-e4d0-0cb828554ca5
Request Method:GET
Status Code:500 Internal Server Error
app.js
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');
var routes = require('./routes/index');
var authRoutes = require("./routes/auth");
var app = express();
//// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// 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(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use("/auth", authRoutes);
auth.js
var express = require('express');
var path = require("path");
var passport = require("passport");
var passportMSLive = require("passport-windowslive");
var app = express();
app.use(passport.initialize());
passport.use(new passportMSLive.Strategy({
clientID: process.env.MSLiveClientID,
clientSecret: process.env.MSLiveClientSecret,
callbackURL: "http://anotherdemoapp.localtest.me:3000/auth/mslive/callback"
},
function (accessToken, refreshToken, profile, done) {
// this callback function will be invoked after successfully login
return done(null, profile);
}
));
// call back
app.get(
"/mslive",
passport.authenticate("windowslive", {
scope: ["wl.offline_access", "wl.contacts_skydrive", "wl.skydrive", "wl.skydrive_update", "wl.signin"]
}),
function (req, res) {
// never enter here
res.send("mslive login");
}
);
app.get(
"/mslive/callback",
passport.authenticate("windowslive", {
failureRedirect: '/mslive/fail'
}),
function (req, res) {
// never enter here
res.send("mslive callback");
}
);
app.get("/mslive/fail", function (req, res) {
// never enter here
res.send("login failed");
});
module.exports = app;
Related
I'm using passport-local for authentication. When starting from login page I do redirect where I should if usr/pwd is correct and redirect back to login when it's not, but if add the authentication requirement to a page I'm always getting redirected to the login page.
app.js
var express = require('express');
var passport = require('passport');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var authRouter = require('./routes/auth');
var listsRouter = require('./routes/lists');
var app = express();
require('./boot/auth')();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.authenticate('session'));
app.use('/', indexRouter);
app.use('/', authRouter);
app.use('/lists', listsRouter);
module.exports = app;
boot/auth.js
var passport = require('passport');
var Strategy = require('passport-local');
module.exports = function () {
passport.use(new Strategy(function (username, password, cb) {
if (checkUsrPwd()) {
var user = {
id: '1',
username: 'my_user',
displayName: 'user name'
};
return cb(null, user);
} else {
return cb(null, false, {
message: 'Incorrect username or password.'
});
}
}));
passport.serializeUser(function (user, cb) {
process.nextTick(function () {
cb(null, {
id: user.id,
username: user.username
});
});
});
passport.deserializeUser(function (user, cb) {
process.nextTick(function () {
return cb(null, user);
});
});
};
routes/lists.js
const express = require('express');
const ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn;
const router = express.Router();
router.get("/list", ensureLoggedIn('/'), (req, res) => {
[...]
res.contentType = 'application/json';
res.render('list', {
userData: items
});
};
});
});
What did I miss?
I was missisng a line in my app.js
app.use(require('express-session')({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
After adding that everything is working fine.
I know that there are numerous posts already referring to the same problem, however, I couldn't find a solution for my case. Here is the relevant code for the issue :
users.js (route)
The login form is submits a POST request to this route.
var express = require('express');
var router = express.Router();
// Require controllers
var usersController = require('../../controllers/usersController');
/* POST login */
router.post('/login', usersController.loginAccount);
module.exports = router;
usersController.js
The passport authentication is handled here.
req.isAuthenticated() returns false here as well. However, successRedirect is executed, which should mean that the user was successfully authenticated.
'use strict';
var bodyParser = require('body-parser');
var mysql = require('mysql');
var bcrypt = require('bcryptjs');
var Client = require('../models/Client');
var passport = require('passport');
var Sequelize = require('sequelize');
var urlencodedParser = bodyParser.urlencoded({ extended: false });
/* POST - Login */
module.exports.loginAccount = function (req, res, next) {
passport.authenticate('local', {
successRedirect: '../dashboard',
failureRedirect: '/users/login',
failureFlash: true
}) (req, res, next);
console.log("Exactly after authentication: " + req.isAuthenticated());
}
index.js (route)
Here, ensureAuthenticated always returns false
var express = require('express');
var router = express.Router();
// Require controllers
var indexController = require('../../controllers/indexController');
/* GET dashboard page */
router.get('/dashboard', ensureAuthenticated, indexController.dashboardPage);
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated())
{console.log("AUTHENTICATED"); return next();}
else{
console.log("NOT AUTHENTICATED");
req.flash('error_msg', 'Please log in to view this resource');
res.redirect('/users/login');
}
}
module.exports = router;
indexController.js
When submitting the login form, this code doesn't get executed, because ensureAuthenticated() is false.
'use strict';
var bodyParser = require('body-parser');
var mysql = require('mysql');
var urlencodedParser = bodyParser.urlencoded({ extended: false });
/* GET - Dashboard page */
module.exports.dashboardPage = function(req, res) {
// console.log(req.user);
// console.log(req.isAuthenticated());
res.render('dashboard');
};
passport.js
const LocalStrategy = require('passport-local').Strategy;
const Sequelize = require('sequelize');
const bcrypt = require('bcryptjs');
// Load User Model
const Client = require('../models/Client');
module.exports = function(passport) {
passport.use(
new LocalStrategy({ usernameField: 'username'}, function(username, password, done) {
// Match User
Client.findOne({ where: {username: username} })
.then(function(user) {
if(!user) {
return done(null, false, { message: 'That username is not registered'});
}
// Match password
bcrypt.compare(password, user.password, function(err, isMatch) {
if(err) throw err;
if(isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Password incorrect'});
}
});
})
.catch(function(err) { console.log(err) });
})
)
passport.serializeUser(function(user, done) {
console.log('Serializing user');
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
console.log('Deserializing user');
console.log('User ID:', id);
Client.findByPk(id)
.then(function(err, user) {
console.log('User ID:', id);
done(err, user);
});
});
}
All the required middleware is setup in the correct order (express-session -> passport.initialize -> passport.session). cookieParser and express-session are set with the same secret (which is otherwise a problem as other posts suggest).
app.js
var createError = require('http-errors');
var express = require('express');
var expressLayouts = require('express-ejs-layouts');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var mysql = require('mysql');
var flash = require('connect-flash');
var session = require('express-session');
var passport = require('passport');
var bodyParser = require('body-parser');
var cors = require('cors');
// Passport config
require('./config/passport')(passport);
var usersController = require('./controllers/usersController');
var indexRouter = require('./api/routes/index');
var usersRouter = require('./api/routes/users');
var roomsRouter = require('./api/routes/rooms');
var app = express();
app.use(cors());
// view engine setup
app.set('views', path.join(__dirname, 'views'));
// EJS
app.use(expressLayouts);
app.use(express.json());
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser('secret'));
app.use(express.static(path.join(__dirname, 'public')));
// Express Session
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}));
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
In your app.js the routes need to be defined after the passpor middleware is set up.
For Example:
var createError = require('http-errors');
var express = require('express');
var expressLayouts = require('express-ejs-layouts');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var mysql = require('mysql');
var flash = require('connect-flash');
var session = require('express-session');
var passport = require('passport');
var bodyParser = require('body-parser');
var cors = require('cors');
// Passport config
require('./config/passport')(passport);
var usersController = require('./controllers/usersController');
var app = express();
app.use(cors());
// view engine setup
app.set('views', path.join(__dirname, 'views'));
// EJS
app.use(expressLayouts);
app.use(express.json());
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser('secret'));
app.use(express.static(path.join(__dirname, 'public')));
// Express Session
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}));
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
var indexRouter = require('./api/routes/index');
var usersRouter = require('./api/routes/users');
var roomsRouter = require('./api/routes/rooms');
Try doing this and see the output
I'm trying to set up Github authentication using passport.
app.js (where i set up middleware)
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
const session = require('express-session');
const passport = require('passport');
const GitHubStrategy = require('passport-github').Strategy;
var indexRouter = require('./routes/index');
var app = express();
const helmet = require('helmet');
app.use(helmet());
const passportConfig = require('./config');
//================================PASSPORT CONFIG=======================
app.use(session({
secret: 'test1234',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new GitHubStrategy(passportConfig,
function (accessToken, refreshToken, profile, cb) {
return cb(null, profile)
}
));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
done(null, user);
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
// 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;
As you can see, I set up express session and use passport.initialize() and passport.session()
But when i try retrieving the req.user object in any of my routes, it returns undefined. Does anyone know what the reason for this might be?
I think this is an issue of app.use(passport.session()); middleware, Manually saving the session before doing any action.
app.get('slack/callback', function(req,res){
passport.authorize('slack');
//Manually save session before redirect.
req.session.save(function(){
res.redirect('/someURL');
});
})
I set up a Google login for my application and am trying to get a unique identifier for the user, so when the user enters a reading I can enter it into the database as that particular user's entry. How can I do this?
Below is some of the login code, I've set up so far. Pretty new to node.js and so the following code will probably be rather sloppy and hacked together. The tutorial I happened to follow split app.js with a file in routes called index.js.
app.js
var express = require('express');
var passport = require('passport');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mongo = require('mongodb');
var monk = require('monk');
var db = monk('localhost:27017/nodetest1');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// 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(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.session());
//Make db accessible to the router
app.use(function(req,res,next){
req.db = db;
next();
});
app.use('/', routes);
app.use('/users', users);
routes/index.js
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
var processRequest = function(token, refreshToken, profile, callback){
process.nextTick(function(){
console.log('id : '+ profile.id);
console.log('name :'+ profile.displayName);
console.log('email :' + profile.emails);
console.log('token : '+ token);
});
};
passport.use(new GoogleStrategy({
clientID: GOOGLE_CLIENT_ID,
clientSecret: GOOGLE_CLIENT_SECRET,
callbackURL: "http://ec2-#########.compute-1.amazonaws.com:8080/Glucometer"
},
function(accessToken, refreshToken, profile, done) {
process.nextTick(function () {
return done(null, profile);
});
}
));
router.get('/auth/google',
passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email'] }),
function(req, res){
// The request will be redirected to Google for authentication, so this
// function will not be called.
});
router.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/' }),
function(req, res) {
res.redirect('/Glucometer');
});
glucometer.jade - The view users are directed to when they log in. Currently, for storing items in the DB I am just having the user type in their username manually. But obviously this is unreliable and I should just have the user type in a reading and the app will handle the timestamp/username entries.
extends layout
block content
h1.
Glucometer Application
table
thead
tr
th Username
th Timestamp
th Blood Sugar
tbody
each reading, i in glucometer
tr
td #{reading.username}
td #{reading.Timestamp}
td #{reading.Bloodsugar}
h1.
Add An Entry
form#formAddEntry(name="glucometer",method="post",action="/glucometer")
input#inputUserName(type="text", placeholder="Username", name="username")
input#inputTimestamp(type="text", placeholder="Timestamp", name="Timestamp")
input#inputBloodsugar(type="text", placeholder="Blood Sugar", name="Bloodsugar")
button#btnSubmit(type="submit") submit
a(href='/logout') Logout
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!