I've asked a similar question before, but I noticed it was in the Javascript section.
I have more specific ideas of what might be going wrong now, as well.
Basically, req.session.passport is empty in my logs. Whenever I start navigating around my site, req.user becomes undefined because the session doesn't have Passport's logged in user anymore.
I would like to know if anyone knows how to solve this? Maybe it's just an error in the configuration of Passport, or the entire Express setup?
App.js:
var express = require("express"),
bodyParser = require("body-parser"),
mongodb = require("mongodb"),
mongoose = require("mongoose"),
uriUtil = require("mongodb-uri"),
morgan = require("morgan"),
session = require("express-session"),
passport = require("passport"),
flash = require("connect-flash"),
ip = "hidden",
port = process.env.PORT || 80
var app = express()
app.disable("x-powered-by")
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
app.use(morgan("dev")); // log every request to the console
// required for passport
app.use(session({
secret: "hidden",
key: 'asdasdasd',
cookie: { maxAge: 60000, secure: false },
resave: true,
saveUninitialized: false
})); // 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
app.set("view engine", "jade")
app.use(express.static(__dirname + "/views"))
require("./includes/passport")(passport)
require("./includes/subject")
require("./includes/user")
Passport.js:
var LocalStrategy = require("passport-local").Strategy,
User = require("./user"),
bCrypt = require('bcrypt-nodejs')
module.exports = function(passport) {
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user._id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called "local"
passport.use('signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : "email",
passwordField : "password",
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ "email" : email }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, req.flash("message", "Dit e-mail-adres is al bezet"));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.email = email;
newUser.password = createHash(password);
newUser.firstname = req.param('firstname');
newUser.lastname = req.param('surname');
newUser.year = parseInt(req.param('year'));
newUser.study = req.param('study');
newUser.courses = req.param('courses');
newUser.phone = req.param('phone');
newUser.availability = req.param('availability');
newUser.description = req.param('descText');
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}));
// =========================================================================
// LOCAL LOGIN =============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use("login", new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : "email",
passwordField : "password",
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ "email" : email }, function(err, user) {
// if there are any errors, return the error before anything else
if (err)
return done(err);
// if no user is found, return the message
if (!user) {
console.log('No user found with email ' + email)
return done(null, false, req.flash('message', 'Gebruiker niet gevonden')); // req.flash is the way to set flashdata using connect-flash
}
if (!isValidPassword(user, password)){
console.log('Incorrect Password');
return done(null, false, req.flash('message', 'Onjuist wachtwoord')); // redirect back to login page
}
// all is well, return successful user
return done(null, user);
});
}));
var isValidPassword = function(user, password){
return bCrypt.compareSync(password, user.password);
}
// Generates hash using bCrypt
var createHash = function(password){
return bCrypt.hashSync(password, bCrypt.genSaltSync(10), null);
}
};
The routes:
api.post("/signup", passport.authenticate("signup", {
successRedirect: "/profile",
failureRedirect: "/",
failureFlash: true
}))
api.post("/login", passport.authenticate("login", {
successRedirect: "/profile",
failureRedirect: "/login"//,
failureFlash: true
}))
router.get("/", function(req, res) {
// serve index.html
res.render("index", {
title: 'Home',
user: req.user,
message: req.flash("message")
})
})
It works on the page that is accessed directly after logging in, which I control as follows:
router.get("/profile", isLoggedIn, function(req, res) {
res.render("profile", {
title: 'Gebruikersprofiel van ' + req.user.firstname + " " + req.user.lastname,
user: req.user // get the user out of session and pass to template
})
})
function isLoggedIn(req, res, next) {
console.log(req.session)
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next()
// if they aren't redirect them to the home page
res.redirect("/login")
}
So far, I've tried adding middleware to add req.user to req.session, and doing the same thing in the login POST. Also I've tried changing the order in which I initialize the middleware in app.js. I am using the new express-session version, without CookieParser, as I read that CookieParser is no longer needed.
If anyone can help me in any way, it would be much appreciated! I've been stuck for a while (as have others).
The problem was not anything I did wrong in setting up the session, or Passport in general, but rather in my links.
I read somewhere that someone was accidentally working in multiple domains (his platform was apparently multi-server), and that made me look through my links this morning.
Apparently, I was linking to my website with www. prefixed, but the session was initialized where there was no www. in front of the URL. I saw this in the cookies.
The solution was, therefore, to link through the website consistently, either having www. prefixed everywhere or nowhere.
Related
I found the following post on how deserializeUser is supposed to work: PassportJS serializeUser and deserializeUser execution flow
However When I try and send a JSON to the server which contains the key for the user, I cannot call req.user to find the user's details.
I am unsure on how to check what is going on because a lot of stuff is going on under the hood.
Does passport expect that I send a cookie to express containing the key? Any specific name for the cookie or format?
Does it require that I sent the key in JSON format?
const express = require('express')
const app = express()
const mongoose = require('mongoose')
var cors = require('cors')
const bodyParser = require('body-parser')
var http = require('http')
var cookieParser = require('cookie-parser');
app.use(cookieParser('someSecret'));
var session = require('express-session');
app.use(session());
var flash=require("connect-flash");
app.use(flash());
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password',
session: true,
passReqToCallback: true
},
function(req, username, password, done){
registrationModel.findOne({username: username}, function(err, user){
if (err) { return done(err); }
if (!user){
console.log("Username incorrect")
return done(null, false, { message: 'Incorrect username.'});
}
if (user.password != password){
console.log("Password Incorrect")
return done(null, false, { message: 'Incorrect Password.'});
} else {
console.log("Returning good stuff")
console.log(user)
return done(null, user);
}
});
}
));
//Needed for authenticating the session and initializing passport
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done) {
console.log("Serializing User")
console.log(user.id)
console.log("Should be serialized")
done(null, user.id);
});
passport.deserializeUser(function(id, done){
users.User.findById(id, function(err, User) {
console.log('attempting to deserialize user')
console.log(user)
console.log('--------------')
if (User){
done(err, User);
} else {
done(err, null);
}
})
})
app.post('/api/authenticate', passport.authenticate('local'),
function(req, res){
const individualIWant = jsonQuery('req.sessionStore.sessions')
res.cookie('FreeUp', req.session.passport.user)
var cookie = JSON.stringify(req.session.passport.user)
res.send({'name': 'FreeUp', 'value': cookie})
})
I can see a cookie in the browser:
name:"FreeUp"
value:""59c4cf4ecb364a000f23a707""
The value is the database ID for the object and not the key for the serialized object. I understand that I need to access the key for serialized object by using res.req.sessionID and to send that back instead.
However the point still stands, I do not know whether to send it back as a json file or a cookie. It seems like such a complex library to use.
Which format does passport expect me to use when sending the data back from Ember?
Thanks!
I had a lot of trouble with this as well.
From what I understand Passport doesn't actually create a session itself. So you need to use another piece of middleware, like express-session, and you'll also need a cookie parser.
I built my authentication using the tutorial they have at Scotch: https://scotch.io/tutorials/easy-node-authentication-setup-and-local. It's really well commented and the only straight forward tutorial I could find (especially for local authentication). I can verify that it worked for me and req.user is storing all the credentials when I pass it in my routes.
Hope that helps.
I am trying to do a basic username/password authentication using passport.js and passport local.
While failureRedirect does exactly what it is supposed to do, (redirects to a specified page), successRedirect keeps pending with the request for its specified page, and after some time, it returns empty response.
http://www.deviantpics.com/VdG
As you can see in this picture, when it is requesting dashboard, it says that its size is 0B, but when I go on that dashboard without redirecting it says it has 1.6B.
I have looked all over Stackoverflow, and I couldn't find an answer that would help me.
Could you please check my code and suggest something before I go berserk?
This is passport load code
//set expression
var expressSession = require('express-session');
app.use(expressSession({
secret: credentials.session.secret
}));
//set passport
var passport = require('passport');
var localStrategy = require('./strategies/auth/local.js');
passport.use('local', localStrategy);
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
app.use(passport.initialize());
app.use(passport.session());
routes.js
module.exports = function(app) {
//main
app.get('/', main.home);
app.get('/login', main.login);
app.get('/signup', main.signup);
app.post('/login', auth.loginLocal);
app.post('/signup', main.checkSignup);
//user
app.get('/user/dashboard', user.dashboard);
app.get('/user/addmemory', user.addMemory);
app.get('/user/memory', user.memory);
login function
exports.loginLocal = passport.authenticate('local', {
successRedirect: '/user/dashboard',
failureRedirect: '/login'
});
local strategy
var localAuthStrategy = new LocalStrategy(function(username, password, done) {
User.findOne({
username: username
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {
message: 'Incorrect username'
});
}
if (!user.validPassword(password)) {
return done(null, false, {
message: 'Incorrect password'
});
}
return done(null, user);
});
});
dashboard function
exports.dashboard = function(req, res) {
res.render('user/dashboard', {
layout: 'user'
});
};
I found an answer to my question, the problem was that the User model was not defined in the script where serializeUser and deserializeUser were defined.
I could not figure out what was going on, because I did not define any action in catch all handler, so a thing to remember, make sure to have catch all handler defined to know what is happening
app.use(function(err, req, res, next) {
console.log(err);
});
I was facing the same problem as your a few days back and what I found was that I forgot to put parenthesis at the end of the serializeUser and deserializeUser functions.
I was actually using the passport-local-mongoose package for the respective functions. But it must be noted that in app.use() the functions are called and executed for all the template files so, we do use parenthesis with the names of the functions.
Have some issues figuring out how to access the current user through my facebook login. I'm using passportJS, Node, express. I think that my 'user' is not staying logged in but I have no way to check. I'll upload what I have and thank you for anyone looking over it - really appreciate it.
route.js
app.get('/auth/facebook', passport.authenticate('facebook', { scope : ['email', 'public_profile', 'user_friends'] }));
// handle the callback after facebook has authenticated the user
app.get('/auth/facebook/callback',
passport.authenticate('facebook', {
successRedirect : '/profile',
failureRedirect : '/'
}));
// route for logging out
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
};
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the home page
res.redirect('/');
}
passport.js
passport.use(new FacebookStrategy({
// pull in our app id and secret from our auth.js file
clientID : configAuth.facebookAuth.clientID,
clientSecret : configAuth.facebookAuth.clientSecret,
callbackURL : configAuth.facebookAuth.callbackURL,
// profileFields: ['id', 'name','picture.type(large)', 'emails', 'username', 'displayName', 'about', 'gender']
},
// facebook will send back the token and profile
function(token, refreshToken, profile, done) {
// asynchronous
process.nextTick(function() {
// find the user in the database based on their facebook id
User.findOne({ 'facebook.id' : profile.id }, function(err, user) {
// if there is an error, stop everything and return that
// ie an error connecting to the database
if (err)
return done(err);
// if the user is found, then log them in
if (user) {
return done(null, user); // user found, return that user
} else {
// if there is no user found with that facebook id, create them
var newUser = new User();
// set all of the facebook information in our user model
newUser.facebook.id = profile.id; // set the users facebook id
newUser.facebook.token = token; // we will save the token that facebook provides to the user
newUser.facebook.name = profile.name.givenName + ' ' + profile.name.familyName; // look at the passport user profile to see how names are returned
newUser.facebook.email = profile.emails[0].value; // facebook can return multiple emails so we'll take the first
console.log(profile);
console.log(user);
console.log('it is working');
// save our user to the database
newUser.save(function(err) {
if (err)
throw err;
// if successful, return the new user
return done(null, newUser);
});
}
});
});
})); // end of FacebookStrategy
};
server.js
require('./config/passport')(passport); // pass passport for configuration
// // required for passport
app.use(session({ secret: 'ilovescotchscotchyscotchscotch' })); // 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
This is my first stackoverflow post so apologies in advanced if I have insulted anyone with the format.
Your user should be serialized some how. For example:
// set up cookie parser and session
var cookieParser = require('cookie-parser');
var session = require('express-session');
app.use(cookieParser());
app.use(session({
secret: 'mysecret',
resave: true,
saveUninitialized: false
}));
// passport init
app.use(passport.initialize());
app.use(passport.session());
// Lets user information be stored and retrieved from session
passport.serializeUser(function(user, done) {
done(null, user.facebook.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err,user){
if(err) done(err);
done(null,user);
});
});
Then you can access the user object via req.user. For example a test route could be:
app.get('/user', function(req, res, next) {
res.send(req.user);
});
Good luck!
You can also do it in another way :
router.get('/auth/facebook', function(req, res, next) {
passport.authenticate('facebook', { scope : ['email', 'public_profile', 'user_friends'] } , function(err, user, info) {
if(err) return res.status(400).send(err);
if(user._id){
req.logIn(user, function(err) {
if (err) { return next(err); }
//redirect where you want
return res.redirect("");
});
}
})(req, res, next);
})
req.logIn is a function which is required with user obj to create session and maintain . Otherwise passport will never able to maintain session of user.
I'm attempting to authenticate a user using Box.com OAuth2.0. I make the initial call and login which redirects to my callback url with the authorization code. At this point my server handles the callback using passport but for some reason it returns a 302 and redirects to the beginning of the oauth authentication process.
//box authentication routes
app.get('/api/box', passport.authorize('box'));
// the callback after box has authorized the user
app.get('/api/box/callback', passport.authorize('box', {
successRedirect: '/',
failureRedirect: '/login'
})
);
I verified that my route is being called by using my own handler and the request data seems to be correct. Box returns a 200 and the url contains the authorization code.
app.get('/api/box/callback', function(req, res) {
console.log('auth called')
});
This is my passport strategy:
passport.use(new BoxStrategy({
clientID: config.box.clientID,
clientSecret: config.box.clientSecret,
callbackURL: config.box.callbackURL,
passReqToCallback: true
},
function(req, accessToken, refreshToken, profile, done) {
process.nextTick(function() {
if(!req.user) {
// try to find the user based on their google id
User.findOne({ 'box.id' : profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
// if a user is found, log them in
return done(null, user);
} else {
// if the user isnt in our database, create a new user
var newUser = new User();
// set all of the relevant information
newUser.box.id = profile.id;
newUser.box.accessToken = accessToken;
newUser.box.refreshToken = refreshToken;
newUser.box.name = profile.name;
newUser.box.email = profile.login;
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
} else {
// user already exists and is logged in, we have to link accounts
var user = req.user;
// update the current users box credentials
user.box.id = profile.id;
user.box.accessToken = accessToken;
user.box.refreshToken = refreshToken;
user.box.name = profile.name;
user.box.email = profile.login;
// save the user
user.save(function(err) {
if (err)
throw err;
return done(null, user);
});
}
});
}
));
Would appreciate any insight as to what might be causing this redirect behavior.
It ended up being an instance of PeerServer that was somehow causing the redirect.
I am trying passport js with google app email id. I am able to authenticate using gmail.com email id. But how can I authenticate if the email id is a google app id (google.com/a/companyname.com).
This is my code
var express = require('express');
var app = express();
var passport = require('passport');
var GoogleStrategy = require('passport-google').Strategy;
passport.use(new GoogleStrategy({
returnURL: 'http://10.3.0.52:3000/auth/google/return',
realm: 'http://10.3.0.52:3000/'
},
function(identifier, profile, done) {
User.findOrCreate({
openId: identifier
}, function(err, user) {
done(err, user);
});
}
));
app.get('/auth/google', passport.authenticate('google'));
app.get('/auth/google/return',
passport.authenticate('google', {
successRedirect: '/',
failureRedirect: '/login'
}));
app.get('/', function(req, res){
res.writeHead(200);
res.end("connected");
});
app.listen(process.env.PORT || 3000);
Your code is missing some vital parts:
...
passport.use(...); // this you have
// these are required as well.
app.use(passport.initialize());
app.use(passport.session());
// please read docs for the following two calls
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(obj, done) {
done(null, obj);
});
...
With those in place, I can log in using my Google App address just fine.
EDIT: it only works with Node 0.8 though, Node 0.10 gives an error. I think using passport-google-oauth is a better solution anyway. For that, you have to register your application with Google (here); after registration, you'll be supplied both the GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET codes which you can use.
I have created a method that verifies if the email domain is the one i want to authorize:
UserSchema.method('checkFordomain', function(value) {
var parts = value.split('#');
return (parts[1] == 'companyname.com');
});
this is method I put in the model of the user model, using mongoose schema models
if (!user.checkForMMdomain(profile.emails[0].value)) {
return done();
}
in the callback of the passport google strategy
https://github.com/jaredhanson/passport-google-oauth
In your passport.use callback you can perform additional checking based on the domain of the primary email address (or whatever you are checking):
if (profile.emails[0].split('#')[1] !== authorizedDomain) {
return done(null, false);
}