Express + Passport - req.session.passport undefined on subsequent requests - javascript

I have started developing little project where I have React with Redux on the client side, and the backend is being done with Node, Express and Passport.js
I will try to describe best What I am struggling with for some hours.
after authentication, when user is being send from server to client, field req.session.passport is set, along with req.user. but when i do next request, no matter is it logout or for example /something/add these fields are undefined.
when authenticating, serializeUser is being called, but deserializeUser not and i dont think it should here, maybe im wrong. as far as I went into debugging the problem, req.login is being called too.
on the next requests it seems that passport isnt doing anything, and i'm out of ideas and anwsers from SO and google. i didnt try the custom callback.
req.session just before sending anwser to client looks like:
Session {
cookie:
{ path: '/',
_expires: 2017-01-11T02:31:49.235Z,
originalMaxAge: 14400000,
httpOnly: false,
secure: false } }
the code on the server side is:
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
global.Models.User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy(
{
usernameField: 'login',
passwordField: 'password',
passReqToCallback: true
},
function(req, login, password, done) {
global.Models.User.logIn({login: login, password: password}, function(err, user){
if(err){
done(err);
}
else{
done(null, user);
}
});
}
));
var app = express();
var router = express.Router();
router.use(cookieParser());
router.use(bodyParser.urlencoded({extended: false}));
router.use(bodyParser.json());
router.use(session({
cookie : {
secure : false,
maxAge : (4 * 60 * 60 * 1000),
httpOnly: false
},
secret: this._config.session.secret,
resave: false,
saveUninitialized: true
}));
router.use(passport.initialize());
router.use(passport.session());
require('./Router')();
app.use(router);
session object here is the express-session. code under is the Router.js required above
var User = require('../Models/User');
var News = require('../Models/News');
var passport = global.Application.getInstanceOf("passport");
function setRoutes(){
router.use(function (req, res, next) {
var log = global.Application.getInstanceOf("logger");
var clientIP = req.headers['x-forwarded-for'] ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress;
log.log("info", req.method + " request from ip: " + clientIP);
res.header('Access-Control-Allow-Origin', 'http://localhost:8080');
res.header('Access-Control-Allow-Credentials', true);
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
if('OPTIONS' == req.method){
res.sendStatus(200);
}
else{
next();
}
});
router.get('/ping', function(req, res){
res.send('ping');
});
router.get('/login/:login', (req, res) => {
Database.client.query(Database.queries.USER_LOGIN, {login: req.params.login}, {useArray: true},
(err, rows) => {
if(err){
res.send({error: "ERROR_DATABASE"});
}
else{
res.send(rows[0][0]);
}
});
});
router.post('/login', passport.authenticate('local', {session: true}),
function(req, res){
console.log(req.session);
req.session.save();
res.send(req.user);
}
);
router.post('/register', (req, res) => {
User.create(req.body, (err, result) => {
if(err){
res.send({error: "ERROR_DATABASE"});
}
res.send(result);
});
});
router.get('/logout', function(req, res){
console.log(req.session);
req.logout();
res.sendStatus(200);
});
router.post('/cms/article', isAuthenticated, (req, res) => {
res.send("BLA");
});
function isAuthenticated(req, res, next){
console.log(req.user);
console.log(req.session);
console.log(req.session.passport);
if(req.isAuthenticated()){
next();
}
else{
res.send("OK");
}
}
}
module.exports = setRoutes;

I have solved the problem.
Explanation:
Cookie was being sent by express to client, but it wasn't saved. For that, it needed change from using $.post to $.ajax with xhrFields option set to {withCredentials: true}.
Aside from that, the problem could also be that, that cookieParser probably need to know cookie secret too now.

Related

Sending individual user data back to client from the server [NodeJS]

I am making a website where users login through Steam. I am able to get their information (such as profile picture and user name) but I've been struggling with sending it back to the client. The json of the user logging in is held within req.user inside of a get request. How would I go about sending the users info from the server to the client of the user that has just logged in?
This is my current code -
// Required to get data from user for sessions
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
// Initiate Strategy
passport.use(new SteamStrategy({
returnURL: 'http://localhost:' + port + '/api/auth/steam/return',
realm: 'http://localhost:' + port + '/',
apiKey: 'xxxxxxxxxxxxxxxxxxxx'
}, function (identifier, profile, done) {
process.nextTick(function () {
profile.identifier = identifier;
return done(null, profile);
});
}
));
app.use(session({
secret: 'LoopTrades',
saveUninitialized: true,
resave: false,
cookie: {
maxAge: 3600000
}
}))
app.use(passport.initialize());
app.use(passport.session());
// Routes
app.get('/', (req, res) => {
res.send(req.user);
});
app.get('/api/auth/steam', passport.authenticate('steam', {failureRedirect: '/'}), function (req, res) {
res.redirect('/')
});
app.get('/api/auth/steam/return', passport.authenticate('steam', {failureRedirect: '/'}), function (req, res) {
res.redirect('/pages/deposit.html');
});

Get username Passport js

I am a beginner and I have simple node application that use passport js.
Everything works but I want to get username here
app.get('/', checkLogged, (req, res) => {
res.render('index', {name: username});
});
Full project here https://github.com/aruzo1/passport
Can anybody help me?
There is way to do this?
Ps. This database is temporary
app.js
if (process.env.NODE_ENV !== 'production'){
require('dotenv').config();
}
const express = require('express'),
app = express(),
port = process.env.PORT || 3000,
bcrypt = require('bcrypt'),
passport = require('passport'),
initializePassport = require('./passport-config'),
flash = require('express-flash'),
session = require('express-session'),
methodOverride = require('method-override'),
users = []
initializePassport(passport,
email => users.find(user => user.email === email),
id => users.find(user => user.id === id)
);
require('ejs');
app.set('view engine', 'ejs');
app.use(express.urlencoded({extended : false}));
app.use(flash());
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(methodOverride('_method'));
app.get('/', checkLogged, (req, res) => {
res.render('index', {name: ""});
});
app.get('/login', checkNotLogged, (req, res) => {
res.render('login', {});
});
app.get('/register', checkNotLogged, (req, res) => {
res.render('register', {});
});
app.post('/register', checkNotLogged, async (req, res) => {
try{
hashedPassword = await bcrypt.hash(req.body.password, 10);
users.push({
id: Date.now().toString(),
name: req.body.name,
email: req.body.email,
password: hashedPassword
});
res.redirect('/login')
}
catch{
res.redirect('/register')
}
});
app.post('/login', checkNotLogged, passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}));
app.delete('/logout', (req, res) => {
req.logOut()
res.redirect('/login')
});
app.listen(port, () => {
console.log('serwer wystartowal')
});
function checkLogged(req, res, next){
if (req.isAuthenticated()){
return next();
}
res.redirect('/login');
}
function checkNotLogged(req, res, next){
if (req.isAuthenticated()){
return res.redirect('/')
}
next()
}
passport-config.js
const localStrategy = require('passport-local').Strategy,
bcrypt = require('bcrypt')
function initialize(passport, getUserByEmail, getUserById){
const authentitaceUser = async (email, password, done) =>{
const user = getUserByEmail(email);
if (user == null){
return done(null, false, {message: 'no user with that email'});
};
try{
if(await bcrypt.compare(password, user.password)){
return done(null, user)
}
else{
return done(null, false, {message: 'wrong password'})
}
}
catch(e){
return done(e)
}
};
passport.use(new localStrategy({
usernameField: 'email'
}, authentitaceUser));
passport.serializeUser((user, done) => {
return done(null, user.id)
});
passport.deserializeUser((id, done) => {
return done(null, getUserById(id))
});
};
module.exports = initialize
res.render('index', {name: req.user.username })
Should do the trick, as long the authentication itself was a success and your user has a 'username' field. Otherwise, req.user.username should throw an error;
Looks like you're using persistent sessions too - you should be able to grab user info from req.user and include it in your response...
app.get('/', checkLogged, (req, res) => {
res.send(req.user);
});
In passport.js when it verifies that user is logged in then the passport.js automatically set the logged-in user info to the res object.So it means whenever user send the request then the req object already having the user info.Here is the function whichdoing this:
passport.setAuthenticatedUser=(req,res,next)=>{
if(req.isAuthenticated())
{
res.locals.user=req.user;
}
next();
}
So in your case when user logged in at that time passport automatically set the user info to every res object.So when any request is coming in that request there is already an user info is present.
So that;s why you need write:
res.render('index', {name: req.user.username })
instead of writing:
res.render('index', {name: username});

Restricting page access with passport.js and express middleware

I have a server set up to authenticate user login, so far I was able to successfully authenticate user and redirect them to the success page (as well as redirect them back to the login page if failed). However, I can't use my own express middleware to restrict user if they are not logged in, for some reason my req.isAuthenticate() check in the middleware is always false. I feel like my session info is not stored when logging in, but I'm not sure.
Here's my setup (note that I use express-flash-2 instead of connect-flash therefore the req.flash())
In server.js
// ...
var flash = require('express-flash-2');
var session = require('express-session');
var passport = require('passport');
// ...
server.use(session({
secret: 'keyboard cat',
resave: true,
saveUninitialized: true
}));
server.use(flash());
server.use(passport.initialize());
server.use(passport.session());
passport.use(auth_controller.authStrategy);
passport.serializeUser(auth_controller.authSerializer);
passport.deserializeUser(auth_controller.authDeserializer);
server.get('/maintenance_login', (req, res) => {
res.render('login');
});
server.post('/maintenance_login', passport.authenticate('local', {
successRedirect: '/maintenance',
failureRedirect: '/maintenance_login',
failureFlash: true
}));
// This does basically the same as above
// server.post('/maintenance_login', (req, res, next) => {
// passport.authenticate('local', function(err, user, info) {
// if (err) { return next(err); }
// if (!user) { return res.redirect('/maintenance_login'); }
//
// req.logIn(user, function(err) {
// if (err) { return next(err); }
// console.log('is authenticated?: ' + req.user); // this returns true
// return res.redirect('/maintenance');
// });
// })(req, res, next);
// });
server.get('/maintenance:query?', auth_controller.restrict, maintenance_controller.maintenance_list);
In auth_controller.js
var passport = require('passport');
var LocalStrategy = require('passport-local');
var User = require('../models/user');
exports.authStrategy = new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
}, function (email, password, done) {
User.authenticate(email, password, function(err, user) {
// success message
// error message
done(err, user, err ? { message: err.message } : null);
});
});
exports.authSerializer = function(user, done) {
done(null, user.id);
};
exports.authDeserializer = function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
};
exports.restrict = function (req, res, next) {
console.log('is authenticated?: ' + req.isAuthenticated()); // This always returns false
if (req.isUnauthenticated()) {
res.flash('error', 'Access denied, please log in.');
return res.redirect('/maintenance_login');
}
return next();
}
Again, my issue is that whenever I was successfully logged in, I got kicked back to /maintenance_login and the flash showing "Access denied, please log in.". Which means that req.isUnauthenticated() in the restrict middleware returns true.
Any ideas?
Well, it turns out that missing the .Strategy is crucial. Changing var LocalStrategy = require('passport-local'); to var LocalStrategy = require('passport-local').Strategy; fixes this issue. Incase anyone else is having the same problem.

Persistent Login with Passport.js no longer working. isAuthenticated returns false

I had this code working at some point and must have lost it in a careless save at some point. I am trying to achieve persistent login with passport but it does not seem to be doing that as I am getting false on the isAuthentiacted middleware.
Here is my primary server.js setup, as you can see the order is good. But I am not sure about the cookie settings as I'm new to this whole thing.
app.use(cookieParser('S3CRE7'));
app.use(bodyParser.json());
app.use(session({ key: 'express.sid', resave: false, saveUninitialized: false, maxAge: 3000}));
app.use(passport.initialize());
app.use(passport.session());
app.use('/users/', usersRouter);
app.use('/transcriptions', transRouter);
app.use(express.static('public'));
const basicStrategy = new BasicStrategy(function(username, password, callback) {
let user;
User
.findOne({username: username})
.exec()
.then(_user => {
user = _user;
if (!user) {
return callback(null, false, {message: 'Incorrect username'});
}
return user.validatePassword(password);
})
.then(isValid => {
if (!isValid) {
return callback(null, false, {message: 'Incorrect password'});
}
else {
return callback(null, user)
}
});
});
passport.use(basicStrategy);
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
Here is my initial Log In endpoint with custom callback function, which logs in just fine, as well as stores a cookie on the client side
router.post('/login', function(req, res, next) {
passport.authenticate('basic', function (err, account) {
req.logIn(account, function() {
res.status(err ? 500 : 200).send(err ? err : account);
});
})(req, res, next)
});
isAuthenticated function:
const isAuthenticated = function (req, res, next) {
if (req.isAuthenticated())
return next();
console.log('not authenticated');
}
First lines of where the authentication fails:
router.get('/', isAuthenticated,
(req, res) => {
console.log(req);
});

Ui-router AngularJS: How to access to session variable 'req.user'

I'm using angular to deal with some routes,on the server side I'm using passport so basically I can acess to the user session variable req.user in my views , but when it comes to a route renderred by ui-router my req.user is undefined. Any idea to access to the req.user even it's not an express route
app.js code :
// Express Session
app.use(session({
secret: 'secret',
saveUninitialized: true,
resave: true
}));
// Passport init
app.use(passport.initialize());
app.use(passport.session());
// Global Vars
app.use(function (req, res, next) {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
res.locals.user = req.user || null;
next();
});
my passport code is as follows :
passport.use('employee',new LocalStrategy(
function(email, password, done) {
Employee.getUserByEmail(email, function(errEmp, emp){
if(errEmp ) throw errEmp;
if(!emp){
return done(null, false, {message: 'Unknown User'});
}
if(emp) {
Employee.comparePassword(password, emp.encryptedpass, function (err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, emp);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
}
});
}
));
router.get('/',ensureAuthenticated ,function(req, res, next) {
res.render('index', { title: 'Nubes' });
});
function ensureAuthenticated(req, res, next){
if(req.isAuthenticated()){
Employee.findById(req.user.id,function (err,emp) {
if(emp) {
res.render('employee/index');
}
})
}
}
router.post('/login', function(req, res, next) {
Employee.findOne({email:req.body.username},function (err,emp) {
if(emp){
passport.authenticate('employee', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res, next);
})
});
In my rendered page 'employee/index' I can display my user information but routes that rendered by ui-router don't have a user variable
here is an example code of angular route :
$stateProvider
.state('home',{
url:'/',
templateUrl:'/views/employee/home.html'
})
in home.html user is not defined which is normal because it's not express server who rendred it . what I want is to get this user variable in my ui-router rendered pages
I suggest to implement token based authentication using something like JWT-tokens, you have also passport plugins for those.
If you still want to use sessions based info and pass it to the client, you can store them in some global JS variable, which i highly dont recommend.
here some info about jwt: https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens
for the locals if using handlebars it would look something like this:
<script>
var user = {{user}};
</script>
just note that you might need to implement some JSON stringify and decoding in order to get the info as JS object.

Categories

Resources