I'm loosely following the tutorial here, and I'm not sure why it's not working. Logging in will work fine -- it accepts and rejects me exactly how I'd expect, it will just not save the session, so visiting any links after will say that I am not authenticated.
Vivaldi dev panel says that no cookies or sessions are saved. I have set it up to save my sessions in redis and user authentication in PostgreSQL, and both databases are connected to fine.
Here is the relevant code:
index.js:
const express = require('express');
const passport = require('passport');
const session = require('express-session');
const Redis = require('ioredis');
const RedisStore = require('connect-redis')(session);
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const auth = require("./app/authenticate");
const config = require('./config');
const app = express();
var redis_client = new Redis({
host: config.redisStore.host,
port: config.redisStore.port,
lazyConnect: true
});
redis_client.connect().catch(function(err) {
throw err;
});
app.use(cookieParser(config.redisStore.secret));
app.use(session({
cookie : {
maxAge: 36000000000,
secure: true
},
secret: config.redisStore.secret,
store: new RedisStore({ client: redis_client }),
resave: false,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.urlencoded({extended: true}));
auth.init.initPassport();
app.post('/login', passport.authenticate('local', {
successRedirect: '/testroute',
failureRedirect: '/'
}));
var urlencodedParser = bodyParser.urlencoded({extended: false});
app.get("/testroute", passport.authenticationMiddleware(), urlencodedParser, function(req, res) {
res.send("You are authenticated!");
});
app.listen(8080);
/app/authenticate/init.js:
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const scrypt = require("scrypt");
const auth = require("./userfunctions");
const authenticationMiddleware = function() {
return function (req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.send('ERR: You are not authenticated!');
};
}
module.exports = {
initPassport: function() {
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(id, done) {
auth.getUserById(id, done);
});
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'pwd',
},
function(username, password, done) {
auth.login(username, function(err, user) {
if (err) {console.log(err); return done(err);}
if (!user) {return done(null, false);}
if (!scrypt.verifyKdfSync(user.password, password)) {return done(null, false);}
return done(null, user);
});
}
));
passport.authenticationMiddleware = authenticationMiddleware;
}
};
There are a few other files in /app/authenticate, which are index.js (just adds all the other things to modules.exports) and userfunctions.js, which just includes login and signup functions. I can post these if you need.
I have also omitted the config file, which is just database credentials for PostgreSQL and redis. Finally I have excluded test.html which is served when you GET /, and is just a test HTML login and signup form.
You can use express-session npm module to save your session value.
Below are the steps-
npm install express-session
In your startup JS file write below code
var expressSession = require('express-session');
app.use(expressSession({secret: 'yourothersecretcode', saveUninitialized: true, resave: true}));
Now you can use req.session in your code
req.session is just a json object that gets persisted by the express-session middleware, using a store of your choice e.g. Mongo or Redis.
Related
The session of my nodejs app is expiring every time I refresh the page, after login. It does work fine if I visit different pages but as soon as I refresh the page, the session ends. I've tried a couple of things but none of it seems to work. How can I keep it from expiring even after the page refresh? If I can store session in the database or someplace else to keep it from expiring.
Here are the files
Passport-init.js
var mongoose = require('mongoose');
var User = mongoose.model('user');
var localStrategy = require('passport-local').Strategy;
var bcrypt = require('bcrypt-nodejs');
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
console.log('serializing user:',user.username);
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
if(err) {
done(500,err);
}
console.log('deserializing user:',user.username);
done(err, user);
});
});
passport.use('login', new localStrategy({
passReqToCallback : true
},
function(req, username, password, done) {
User.findOne({'username': username},
function(err, user) {
if(err) {
return done(err);
}
if(!user) {
console.log("UserName or Password Incorrect");
return done(null, false);
}
if(!isValidPassword(user, password)) {
console.log("UserName or Password is Incorrect");
return done(null, false);
}
return done(null, user);
});
}));
passport.use('signup', new localStrategy({
passReqToCallback : true
}, function(req, username, password, done) {
User.findOne({'username': username},
function(err, user) {
if(err) {
console.log("Error in signup");
return done(err);
}
if(user) {
console.log("Username already exist" + username);
return(null, false);
}
else {
var newUser = new User();
newUser.username = username;
newUser.password = createHash(password);
newUser.save(function(err) {
if(err) {
console.log("Error in saving user");
throw err;
}
console.log(newUser.username + ' Registration succesful');
return done(null, newUser);
});
}
});
}));
var isValidPassword = function(user, password) {
return bcrypt.compareSync(password, user.password);
}
var createHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(10), null);
}
};
Auth.js
var express = require('express');
var router = express.Router();
module.exports = function(passport) {
router.get('/success', function(req, res) {
res.send({state: 'success', user: req.user ? req.user : null});
});
router.get('/failure', function(req, res) {
res.send({state: 'failure', user: null, message: 'Invalid Username or Password'});
});
router.post('/login', passport.authenticate('login', {
successRedirect: '/auth/success',
failureRedirect: '/auth/failure'
}));
router.post('/signup', passport.authenticate('signup', {
successRedirect: '/auth/success',
failureRedirect: '/auth/failure'
}));
router.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
return router;
};
Server.js
var express = require('express');
var path = require('path');
var app = express();
var server = require('http').Server(app);
var logger = require('morgan');
var passport = require('passport');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var mongoose = require('mongoose');
var MongoStore = require('connect-mongo')(session);
mongoose.connect("mongodb://localhost:27017/scriptknackData");
require('./models/model');
var api = require('./routes/api');
var auth = require('./routes/auth')(passport);
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());
app.use(session({
secret: 'super secret key',
resave: true,
cookie: { maxAge: 60000 },
saveUninitialized: true,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
var initpassport = require('./passport-init');
initpassport(passport);
app.use('/api', api);
app.use('/auth', auth);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
var port = process.env.PORT || 3000;
server.listen(port, function() {
console.log("connected");
});
As per express-session documentation
cookie.maxAge
Specifies the number (in milliseconds) to use when calculating the Expires Set-Cookie attribute. This is done by taking the current server time and adding maxAge milliseconds to the value to calculate an Expires datetime. By default, no maximum age is set.
And use express.session() before passport.session() to ensure login session is stored in correct order. passport docs
In your case you have specified maxAge as 60000ms (60sec) only. Try this:
...
app.use(session({
secret: 'super secret key',
resave: true,
cookie: { maxAge: 8*60*60*1000 }, // 8 hours
saveUninitialized: true,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
app.use(passport.initialize());
app.use(passport.session());
...
Increase your cookie maxAge value according to your need, it will solve your issue.
I was facing the same issue as you and I got the problem fixed by doing this:
If anyone is having issues, this could probably help to solve it.
app.use(session({
secret: "our-passport-local-strategy-app",
resave: true,
saveUninitialized: true,
cookie: {
maxAge: 24 * 60 * 60 * 1000
},
store: new MongoStore({
mongooseConnection: mongoose.connection,
ttl: 24 * 60 * 60 // Keeps session open for 1 day
})
}));
I had this problem and I found out how to fix it. In my case, this problem was just during using localhost during running react app on own port. I use the build production version, there was no problem. But it is not good to run build every time you need to see changes.
First I run Nodejs on 5000 port at localhost.
In React's package.json, I added "proxy": "http://localhost:5000/". After that, I ran react app on port 3000. Now when I use fetch, the URL to my API is not http://localhost:5000/api/login but just /api/login.
You can read more about that here:
https://create-react-app.dev/docs/proxying-api-requests-in-development/
Do not forget to remove the proxy from package.json when you will deploy to the server. This is good only for the development version.
As per the fine manual (emphasis mine):
Note that enabling session support is entirely optional, though it is recommended for most applications. If enabled, be sure to use express.session() before passport.session() to ensure that the login session is restored in the correct order.
In your case, the order is not correct. Try this:
...
app.use(session({
secret: 'super secret key',
resave: true,
cookie: { maxAge: 60000 },
saveUninitialized: true,
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
app.use(passport.initialize());
app.use(passport.session());
...
I have a project using passportjs fully working, but not showing flash messages.
The passportjs file looks like this:
passport.use('local-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 in the req from our route (lets us check if a user is logged in or not)
},
function (req, email, password, done) {
if (email) {
email = email.toLowerCase()
} // Use lower-case e-mails to avoid case-sensitive e-mail matching
// asynchronous
process.nextTick(function () {
User.findOne({ 'local.email': email }, function (err, user) {
// if there are any errors, return the error
if (err) {
console.log(err)
return done(err)
}
// if no user is found, return the message
if (!user) {
console.log('No user found')
return done(null, false, req.flash('message', 'No user found'))
}
My routes.js file looks like this:
// Login
app.get('/login', function (req, res) {
console.log('login get')
res.render('pages/login', {message: req.flash('messsage')})
})
my login.ejs file looks like this:
<%if (message) {%>
<%=message%>
<%}%>
I have no idea why it isn't working?
Here comes my server.js if it is any problem related to includes:
var express = require('express')
var mongoose = require('mongoose')
var passport = require('passport')
var path = require('path')
var ejs = require('ejs') // Not used?
var fs = require('fs') // Not used?
const session = require('express-session')
const MongoStore = require('connect-mongo')(session)
// Reads .env variables for encrypted data
require('dotenv').config()
var port = process.env.PORT || 8080
var db = process.env.MONGO_URI
mongoose.connect(db) // connect to our database
var app = express()
app.set('views', './views')
app.set('view engine', 'ejs')
// GET /public/style.css etc.
app.use(express.static(path.join(__dirname, '/public')))
var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded())
app.use(session({
secret: 'hakunamatata',
store: new MongoStore({
mongooseConnection: mongoose.connection,
saveUninitialized: false,
resave: false
})
}))
var flash = require('connect-flash')
app.use(flash())
var initPassport = require('./app/authentication/passport')
initPassport(passport)
app.use(passport.initialize())
app.use(passport.session()) // persistent login sessions
require('./app/routes/routes')(app, passport)
app.listen(port)
console.log('Dev port is: ' + port)
I tested with:
req.flash('loginMessage', 'No user found')
instead of:
req.flash('message', 'No user found')
and on the routes.js file:
{message: req.flash('loginMessage')}
instead of:
{message: req.flash('message')}
And now it works... I dont know what made the difference, but I hope this can help someone else in the future..
Yes, I see that this question has been asked here and here, but the answers point to either making changes to your deserializeUser callback, or changing something in your Mongoose model.
I've tried the first to no avail and am using the regular ol' NodeJS driver, so I'm not quite sure where to pinpoint the root cause of my issue.
Here's my script:
AUTHENTICATE.JS:
var app = require('express');
var router = app.Router();
var assert = require('assert');
var bcrypt = require('bcrypt');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
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);
});
}
));
router.post('/login',
passport.authenticate('local', {successRedirect:'/',
failureRedirect:'/login',failureFlash: false}),
function(req, res) {
res.redirect('/');
});
For my app.js file I've tried a number of the fixes suggested in similar questions but nothing has made a difference. This is what it looks like:
APP.JS:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var expressValidator = require('express-validator');
var passport = require('passport');
var localStrategy = require('passport-local').Strategy;
var mongo = require('mongodb').MongoClient;
var session = require('express-session');
var bcrypt = require('bcrypt');
// Express Session
app.use(session({
secret: 'keyboard cat',
saveUninitialized: true,
resave: true,
cookie: {secure: true}
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
//initialize passport for app
app.use(passport.initialize());
app.use(passport.session());
// make mongodb available to the application
app.use((req, res, next) => {
mongo.connect('mongodb://localhost:27017/formulas', (e, db) => {
if (e) return next(e);
req.db = db;
next();
});
});
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.use(express.static(__dirname + '/public'));
// Express Validator
app.use(expressValidator({
errorFormatter: function(param, msg, value) {
var namespace = param.split('.')
, root = namespace.shift()
, formParam = root;
while(namespace.length) {
formParam += '[' + namespace.shift() + ']';
}
return {
param : formParam,
msg : msg,
value : value
};
}
}));
//define routes here
app.set('port', (process.env.PORT || 3000));
app.listen(app.get('port'), function(){
console.log("The server is now listening on port "+app.get('port'));
});
module.exports = app;
Any help would be greatly appreciated, thank you.
As both questions you included point out, you need to define the User class first before you can use it. It's not something that passportjs or expressjs provide, you need to implement it for yourself or use another module that gives you that functionality (like mongoose).
In the first SO link you shared the answer suggested the OP implement a user model (User) in mongoose (it seems to be a popular choice).
The second links answer simplified things a bit by adding a hard-coded object to represent the user in the deserializer function.
I'm new to MEAN stack and I'm trying to setup a simple social login using google passport strategy. I can successfully authenticate myself, but when calling a redirect on success, the middle ware function isLoggedIn keeps showing req.isAuthenticated() to be false. Below are code snippets. I saw that there were multiple posts on this issue but none of the answers seem to work for me. Kindly help me resolve this issue.
passport.js
var Auth = require('./auth.js');
var ubCust = require('../models/ubCust.js');
var FacebookStrategy = require('passport-facebook').Strategy;
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
//var FacebookStrategy = require('passport-facebook').Strategy;
module.exports= function(passport){
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
ubCust.findById(id,function(err,user){
done(err, user);
})
});
passport.use(new GoogleStrategy ({
clientID: Auth.googleAuth.clientID,
clientSecret: Auth.googleAuth.clientSecret,
callbackURL : Auth.googleAuth.callbackURL
},
function(token, refreshToken, profile, done) {
// Create or update user, call done() when complete...
process.nextTick(function(){
ubCust.findOne({'google.id' : profile.id}, function(err, user) {
if (err)
return done(err);
if(user)
return done(null,user);
else
{
var newUser = new ubCust;
newUser.google.id = profile.id;
newUser.google.token = token;
newUser.google.name = profile.displayName;
newUser.google.email = profile.emails[0].value;
newUser.save(function(err){
if (err)
throw err;
return done(null,newUser);
});
console.log(profile);
}
//done(null, profile, tokens);
}); //findOne
});//nextTick
}
));
};
route(authController.js)
module.exports = function(app,passport){
app.get('/api/getprofauth',isLoggedIn,function(req,res){
console.log('In getprofile authentication api');
//console.log('req.query :',req.query);
res.send(req.user);
});
app.get('/auth/google',
passport.authenticate('google',{scope: ['email','profile']})
);
app.get('/auth/google/callback',
passport.authenticate('google', {failureRedirect: '/'}),
function(req, res) {
console.log('auth success!! ',req.isAuthenticated(),req.user);
res.redirect('/api/getprofauth');
}
);
function isLoggedIn(req,res,next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
{
console.log('isAuthenticated Success');
return next();
}
else{
console.log('req.user',req.user,req.isAuthenticated());
console.log('isAuthenticated Failure');
res.redirect('/');
}
// if they aren't redirect them to the home page
}//isLoggedIn
}
app.js(server)
var express = require('express');
var app = express();
var mongoose = require('mongoose');
var config = require('./config');
var passport = require('passport');
var cookieParser = require('cookie-parser');
app.use(cookieParser());
var session = require('express-session');
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
var authController = require('./controllers/authController.js');
var port = process.env.PORT||3000;
app.use(express.static(__dirname+ '/public'));
app.set('view engine','ejs');
app.get('/',function(req,res){
//redirecting request to home page '/' to index page
res.redirect('/index.htm');
});
mongoose.connect(config.getDBConnectionString());
app.use(passport.initialize());
app.use(passport.session());
var pp = require('./config/passport');
pp(passport);
apiController(app);
apibike(app);
appoController(app);
authController(app,passport);
app.listen(port);
i'm developing application on cloud9 enviroment. using:
node 4.43
express 4.13.4
i have integrated my Demo Auth0 account into my on-dev application.
i am able to login (being redirected to the first page of my app), but when i'm printing req.isAuthenticated() i'm getting false. also req.user is undefined.
i have followed the quick start of auth0 for node.js.
i'm attaching the three files that are mainly invovled:
app.js:
var express = require('express'),
app = express(),
BodyParser = require("body-parser"),
mongoose = require("mongoose"),
student = require ("./models/student"),
students_class = require("./models/class"),
// =============
// auth0
// =============
passport = require('passport'),
strategy = require('./models/setup-passport'),
cookieParser = require('cookie-parser'),
session = require('express-session');
app.use(cookieParser());
app.use(session({ secret: 'FpvAOOuCcSBLL3AlGxwpNh5x-U46YCRoyBKWJhTPnee2UELMd_gjdbKcbhpIHZoA', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());
app.get('/login',passport.authenticate('auth0', { failureRedirect: '/url-if-something-fails' }),
function(req, res) {
res.send(req.user);
if (!req.user) {
throw new Error('user null');
}
res.redirect("/", {username: req.user});
});
mongoose.connect("mongodb://localhost/myapp");
// ============================
// routes
// ============================
var classRoutes = require("./routes/class"),
indexRoutes = require("./routes/index"),
studentRoutes = require("./routes/student"),
assocRroutes = require ("./routes/assoc");
// ============================================
// configuring the app
// ============================================
app.set("view engine", "ejs");
app.use(express.static ("public"));
app.use(BodyParser.urlencoded({extended: true}));
app.use(classRoutes);
app.use (indexRoutes);
app.use(studentRoutes);
app.use(assocRroutes);
app.listen(process.env.PORT, process.env.IP, function() {
console.log('Attendance Server is Running ....');
});
setup-passport.js
var passport = require('passport');
var Auth0Strategy = require('passport-auth0');
var strategy = new Auth0Strategy({
domain: 'me.auth0.com',
clientID: 'my-client-id',
clientSecret: 'FpvAOOuCcSBLL3AlGxwpNh5x-U46YCRoyBKWJhTPnee2UELMd_gjdbKcbhpIHZoA',
callbackURL: '/callback'
}, function(accessToken, refreshToken, extraParams, profile, done) {
// accessToken is the token to call Auth0 API (not needed in the most cases)
// extraParams.id_token has the JSON Web Token
// profile has all the information from the user
return done(null, profile);
});
passport.use(strategy);
// This is not a best practice, but we want to keep things simple for now
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
module.exports = strategy;
index.js (the actual fisrt page where i want to re-direct after successful login:
var express = require("express");
var passport = require('passport');
var ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn();
var router = express.Router();
var student = require ("../models/student");
//INDEX
router.get("/callback", function(req, res) {
student.find({}, function(err, student) {
console.log(req.isAuthenticated())
if (err) {
console.log(err);
} else {
res.render("home/index.ejs", {
students: student
});
}
});
});
module.exports = router;
any suggestion what could go wrong?
also wierd for me that on app.js, the guide is initializing the variable strategy but actually never seem to use it.
BUMP
You are not calling passport.authenticate() in the /callback endpoint. See for comparison: https://auth0.com/docs/quickstart/webapp/nodejs#5-add-auth0-callback-handler
// Auth0 callback handler
app.get('/callback',
passport.authenticate('auth0', { failureRedirect: '/url-if-something-fails' }),
function(req, res) {
if (!req.user) {
throw new Error('user null');
}
res.redirect("/user");
});