Session is not working + express - javascript

I am using express-session in my app. What i have tried is (POC):.
server.js
app.use(session({
secret: 'pal!lap789',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
key: 'user_sid',
resave: false,
cookie: { secure: false, httpOnly: false }
}));
app.get('/abcd', sessionChecker, function(req, res){
res.send("hiiiii");
});
app.get('/session', (req, res) => {
req.session.user = "subbuvlb#gmail.com";
res.send("hgdhjdgjds")
});
Its working properly,
But when i try to integrate with my project ,its not working.
app.use(session({
secret: 'pal!lap789',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
key: 'user_sid',
resave: false,
cookie: { secure: false, httpOnly: false }
}));
var usersRouter = require('./router/users');
app.use('/users', usersRouter);
router/user.js
const express = require('express'); -------------> New express instantiated.
const router = express.Router();
router.post('/register', (req, res, next) => {
req.session.user = "emailid"
});
What i am trying to achieve is have to check if user session is there for each resquest,
so i modified my server.js file as follows:
app.use(session({
secret: 'pal!lap789',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
key: 'user_sid',
resave: false,
cookie: { secure: false, httpOnly: false }
}));
var usersRouter = require('./router/users');
app.use('/users', usersRouter);
var sessionChecker = (req, res, next) => {
console.log(req.session.user) --------------------------->Undefined
if (req.session.user && req.cookies.user_sid) {
next();
} else {
res.redirect('/login');
}
};
var usersRouter = require('./router/users');
app.use('/users',sessionChecker, usersRouter);
Why the req.user.undefined if i specify router files in server.js. I think i explained clearly, ready to give more input if needed. Please provide ur ideas. Thanks in advance.

define global variable in your server.js file
global.express = require('express');
global.app = express();
global.session = require('express-session');
app.use(session({
secret: 'pal!lap789',
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
key: 'user_sid',
resave: false,
cookie: { secure: false, httpOnly: false }
}));
var sessionChecker = (req, res, next) => {
if (req.session.user && req.cookies.user_sid) {
next();
} else {
res.redirect('/login');
}
};
var usersRouter = require('./router/users');
app.use('/users',sessionChecker, usersRouter);
in your router/user.js
const router = express.Router(); // use global express defined in server.js
router.post('/register', (req, res, next) => {
req.session.user = "emailid"
});

Finally i got the trick,
I am checking from Angular.js front-end, by default Angular will not include Cookies, so i have set {"withCredentials": "true"} in each Request from Angular Front-end.

Related

Express could not store cookie

I am trying to store a login-session into a cookie when a user login in via username/passport, so the server knows the user is logged in. But the cookie will never be set.
Here is the relevant code:
index.js:
if (process.env.NODE_ENV !== 'production') {
require("dotenv").config();
}
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
app.use(bodyParser.json({ limit: "16mb", extended: true }));
app.use(bodyParser.urlencoded({ extended: true, limit: "16mb" }));
const session = require("express-session");
app.use(
session({
secret: "thisIsMySecretMessageHowWillYouGuessIt",
resave: true,
saveUninitialized: true,
cookie: {
sameSite: 'none',
httpOnly: true,
secure: true
},
})
);
const passport = require("passport");
app.use(passport.initialize());
app.use(passport.session());
const cookieParser = require("cookie-parser");
app.use(cookieParser());
const cors = require("cors");
const whitelist = env.process.CLIENT_URL;
app.use(cors({ origin: whitelist, credentials: true }));
auth.js:
const cookieKey = "sid";
const md5 = require("md5");
const bcrypt = require("bcrypt");
const redis = require("redis");
const client = redis.createClient(process.env.REDIS_URL);
const cookieOption = { maxAge: 3600 * 1000, httpOnly: true, sameSite: 'none', secure: true};
login = async (req, res) => {
const sessionKey = md5(
getSecretMessage() + new Date().getTime() + user.username
);
client.hmset("sessions", sessionKey, JSON.stringify(user), function(err) {
if (err) throw err;
});
// this sets a cookie
res.cookie(cookieKey, sessionKey, cookieOption); // expire after 60 mins
res.send({ username: user.username, result: "success" });
};
isLoggedIn = async (req, res, next) => {
if (
(req.cookies === undefined || req.cookies[cookieKey] === undefined) &&
!req.isAuthenticated()
) {
res.sendStatus(401);
return;
}
};
The req.cookies['sid'] will always be undefined, so the server would return 401 status.
For the react client, the 'credentials' has been set to 'include'.
Things I tried:
Flipping around the 'secure' values in the cookie option in both index.js and auth.js
Used 'express-samesite-default' package
One point to notice is that the functionality was working half-year ago, there might be some dependencies update so it changed the cookie.
You could use local storage.Local storage saves on the clients device and is accessible using localStorage.getItem('key') and you can add items by using the localStorage.setItem('key', 'value').

passport.js not passing user to session

I'm trying to create an app with passport.js, node and sequelize.
But, passport is not returning the user in the session as expected.
When I log req.session I get this:
Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true,
secure: true } }
when I log req.session.passport I get undefined.
How can I fix this?
This is my server.js:
const express = require('express');
const load = require('express-load');
const passport = require('passport');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const session = require('express-session');
// var app = express();
var app = module.exports = express();
// read cookies (needed for auth)
app.use(cookieParser());
// get information from html forms
app.use(bodyParser());
//set session
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret: 'asdasdsada',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}))
// required for passport
app.use(passport.initialize());
app.use(passport.session({
secret: 'adsdssa',
name: 'sadasd',
proxy: true,
resave: true,
saveUninitialized: true
}));
And this is my passport.js:
var LocalStrategy = require('passport-local').Strategy;
var SlackStrategy = require('passport-slack').Strategy;
var User = require('../models/index').User;
var mysql = require('mysql');
var connection = mysql.createConnection({
host : process.env.MYSQL_HOST,
user : process.env.MYSQL_USER,
password : process.env.MYSQL_PASSWORD,
database : process.env.MYSQL_DB
});
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
console.log('-----------serialize');
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
console.log('----------deserialize');
Model.User.findOne({
where: {
'id': id
}
}).then(function (user) {
if (user == null) {
done(new Error('Wrong user id.'));
}
done(null, user);
})
});
passport.use('slack', new SlackStrategy({
clientID: process.env.SLACK_ID,
clientSecret: process.env.SLACK_SECRET,
callbackURL: process.env.SLACK_REDIRECT,
scope: "incoming-webhook users:read"
},
function(accessToken, refreshToken, profile, done) {
var values = {
where: { slack_id: profile.id },
defaults: {slack_id: profile.id, name: profile.displayName}
};
User.findOrCreate(values)
.spread(function(user, created) {
return done(null,user);
});
}
));
And these are the routes I'm using:
app.get('/auth/slack',
passport.authorize('slack'));
app.get('/auth/slack/callback',
passport.authorize('slack', { failureRedirect: '/login' }),
function(req, res) {
//Successful authentication, redirect home.
console.log(req.session);
console.log(req.session.passport);
res.redirect('/dashboard');
}
);
I had the same problem and solved it.
Just remove
secure: true
for session like that
//set session
app.use(session({
secret: 'asdasdsada',
resave: false,
saveUninitialized: true
}))
It should works Also you can see simple example of passport-local here
https://github.com/passport/express-4.x-local-example

Persistent login stopped working with Node.js, Express, PassportJS, Connect-Mongo

At some point persistent login with my application stopped working and I have no idea why. The thing is that even when I simply refresh the page, the app, the user is logged out. I built this application off of scaffolding provided by MEAN.js, so I'm having trouble locating the problem. Can I please have help debugging this? Any help appreciated.
Heres my express setup file
var fs = require('fs'),
http = require('http'),
https = require('https'),
express = require('express'),
morgan = require('morgan'),
bodyParser = require('body-parser'),
session = require('express-session'),
compress = require('compression'),
acl = require('acl'),
methodOverride = require('method-override'),
cookieParser = require('cookie-parser'),
helmet = require('helmet'),
passport = require('passport'),
mongoStore = require('connect-mongo')({
session: session
}),
flash = require('connect-flash'),
config = require('./config'),
consolidate = require('consolidate'),
path = require('path');
module.exports = function(db) {
// Initialize express app
var app = express();
// Globbing model files
config.getGlobbedFiles('./app/models/**/*.js').forEach(function(modelPath) {
require(path.resolve(modelPath));
});
/**
* Configure the modules ACL policies
*/
// Globbing policy files
config.getGlobbedFiles('app/policies/*.js').forEach(function(policyPath) {
require(path.resolve(policyPath)).invokeRolesPolicies();
});
// Setting application local variables
app.locals.title = config.app.title;
app.locals.description = config.app.description;
app.locals.keywords = config.app.keywords;
app.locals.facebookAppId = config.facebook.clientID;
app.locals.jsFiles = config.getJavaScriptAssets();
app.locals.cssFiles = config.getCSSAssets();
// Passing the request url to environment locals
app.use(function(req, res, next) {
res.locals.url = req.protocol + '://' + req.headers.host + req.url;
next();
});
// Should be placed before express.static
app.use(compress({
filter: function(req, res) {
return (/json|text|javascript|css/).test(res.getHeader('Content-Type'));
},
level: 9
}));
// Showing stack errors
app.set('showStackError', true);
// Set swig as the template engine
app.engine('server.view.html', consolidate[config.templateEngine]);
// Set views path and view engine
app.set('view engine', 'server.view.html');
app.set('views', './app/views');
// Environment dependent middleware
if (process.env.NODE_ENV === 'development') {
// Enable logger (morgan)
app.use(morgan('dev'));
// Disable views cache
app.set('view cache', false);
} else if (process.env.NODE_ENV === 'production') {
app.locals.cache = 'memory';
}
// Request body parsing middleware should be above methodOverride
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(methodOverride());
// CookieParser should be above session
app.use(cookieParser());
// Express MongoDB session storage
app.use(session({
saveUninitialized: true,
resave: true,
secret: config.sessionSecret,
cookie: {
maxAge: config.sessionCookie.maxAge,
httpOnly: config.sessionCookie.httpOnly,
secure: config.sessionCookie.secure && config.secure.ssl
},
key: config.sessionKey,
store: new mongoStore({
db: db.connection.db,
collection: config.sessionCollection
})
}));
// use passport session
app.use(passport.initialize());
app.use(passport.session());
// connect flash for flash messages
app.use(flash());
// Use helmet to secure Express headers
app.use(helmet.xframe());
app.use(helmet.xssFilter());
app.use(helmet.nosniff());
app.use(helmet.ienoopen());
app.disable('x-powered-by');
// Setting the app router and static folder
app.use(express.static(path.resolve('./public')));
// Globbing routing files
config.getGlobbedFiles('./app/routes/**/*.js').forEach(function(routePath) {
require(path.resolve(routePath))(app);
});
// Assume 'not found' in the error msgs is a 404. this is somewhat silly, but valid, you can do whatever you like, set properties, use instanceof etc.
app.use(function(err, req, res, next) {
// If the error object doesn't exists
if (!err) return next();
// Log it
console.error(err.stack);
// Error page
res.status(500).render('500', {
error: err.stack
});
});
// Assume 404 since no middleware responded
app.use(function(req, res) {
res.status(404).render('404', {
url: req.originalUrl,
error: 'Not Found'
});
});
if (process.env.NODE_ENV === 'secure') {
// Log SSL usage
console.log('Securely using https protocol');
// Load SSL key and certificate
var privateKey = fs.readFileSync('./config/sslcerts/key.pem', 'utf8');
var certificate = fs.readFileSync('./config/sslcerts/cert.pem', 'utf8');
// Create HTTPS Server
var httpsServer = https.createServer({
key: privateKey,
cert: certificate
}, app);
// Return HTTPS server instance
return httpsServer;
}
// Return Express server instance
return app;
};
Result of Console Log of Config Object
{ root: '/Users/yako/Developer/ronny/trunk/meanjs',
app: { title: 'Dyad Medical - Development Environment' },
sessionCookie: { maxAge: 86400000, httpOnly: true, secure: false },
port: 3000,
templateEngine: 'swig',
sessionSecret: 'XXXXXXXXXX',
sessionCollection: 'sessions',
sessionKey: 'sessionId',
assets:
{ lib: { css: [Object], js: [Object] },
css: [ 'public/modules/**/css/*.css' ],
js:
[ 'public/config.js',
'public/application.js',
'public/modules/*/*.js',
'public/modules/*/*[!tests]*/*.js' ],
tests:
[ 'public/lib/angular-mocks/angular-mocks.js',
'public/modules/*/tests/*.js' ] },
db: 'mongodb://localhost/medical-dyad-dev',
facebook:
{ clientID: 'APP_ID',
clientSecret: 'APP_SECRET',
callbackURL: '/auth/facebook/callback' },
twitter:
{ clientID: 'CONSUMER_KEY',
clientSecret: 'CONSUMER_SECRET',
callbackURL: '/auth/twitter/callback' },
google:
{ clientID: 'APP_ID',
clientSecret: 'APP_SECRET',
callbackURL: '/auth/google/callback' },
linkedin:
{ clientID: 'APP_ID',
clientSecret: 'APP_SECRET',
callbackURL: '/auth/linkedin/callback' },
github:
{ clientID: 'APP_ID',
clientSecret: 'APP_SECRET',
callbackURL: '/auth/github/callback' },
mailer:
{ from: 'MAILER_FROM',
options: { service: 'gmail', auth: [Object] } },
seedDB:
{ seed: false,
options: { logResults: true, seedUser: [Object], seedAdmin: [Object] } },
getGlobbedFiles: [Function],
getJavaScriptAssets: [Function],
getCSSAssets: [Function] }
Your app has this setting for cookies:
cookie: {
maxAge: config.sessionCookie.maxAge,
httpOnly: config.sessionCookie.httpOnly,
secure: config.sessionCookie.secure && config.secure.ssl
},
Since config.sessionCookie.secure is always false, then the line above will always resolve as false. Also, there is no setting anywhere for the property config.secure.ssl
If you are using HTTPS, then you should ensure that cookie.secure is set to true. One way to fix it is to get the SSL setting higher up in the code like this:
var secureConfig = (process.env.NODE_ENV === 'secure') ? true:false;
And then use that to set the cookie config line to the following:
cookie: {
maxAge: config.sessionCookie.maxAge,
httpOnly: config.sessionCookie.httpOnly,
secure: secureConfig
},
you need to save the user session data when user successfully login to Session Storage/Local Storage or global.window, so it become persistent even after the user refresh the page. From there you can always compare the client sessionId and mongoDb user sessionId using standard HTTP request.

How configure Redis Store for my production env?

I am trying to setup Redis for a session store, but is not working at. I'm using passport.js and express-flash, and if I try run the current Redis setup, it won't work:
var session = require('express-session');
var favicon = require('serve-favicon');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var redis = require("redis").createClient();
var RedisStore = require("connect-redis")(session);
var load = require('express-load');
var flash = require('express-flash');
var path = require('path');
var logger = require('morgan');
var i18n = require('i18n-2');
var passport = require('passport');
var mongoose = require('mongoose');
If I use this session setup:
app.use(session({
secret: 'keyboard cat'
}));
This will show an error saying that is not safe for use in production, however the passport.js and the express-flash will work.
Moving on to Redis:
app.use(session({
store: new RedisStore({
host: 54.94.171.197,
port: 3000,
client: redis
}),
secret: 'keyboard cat'
}));
Should I put the static IP in the host and the 3000 in the port? I am very confused with the proper values that I need pass to the new instance.
This is my middleware:
app.use(favicon(__dirname + '/public/images/icons/fav.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(flash());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
store: new RedisStore({
host: global.config.site.host,
port: 6379,
client: redis
}),
secret: 'keyboard cat'
}));
// Productions Middlewares
if (process.env.NODE_ENV === 'production') {
app.use(passport.initialize());
app.use(passport.session());
app.use('/admin', middleware.ensureAuthenticated);
app.use(middleware.ensureHttps);
}
It’s bad practice to have your application’s configuration inside the code.
Use something like nconf to have your configuration out of the code.
For example you could use a config.json file:
{
"sessionSecret": "cat something",
"redis": {
"host": "localhost",
"port": 6379
}
}
Configure nconf to look for the configuration file
var nconf = require('nconf');
nconf.file({ file: '/path/to/config.json' })
Then use the configuration in your session middleware
app.use(session({
store: new RedisStore({
host: nconf.get('redis:host'),
port: nconf.get('redis:port'),
client: redis
}),
secret: nconf.get('sessionSecret')
}));

How do I set a session cookie to secure and use CSRF tokens?

I have an express application where I am trying to set the session cookie to secure. So far I have tried the code below:
app.use(express.cookieParser());
sessionOptions = definitions.REDIS;
sessionOptions.ttl = definitions.session.expiration;
app.use(express.session({
secret: definitions.session.secret,
cookie: { <---------------------------- Added this
secure: true
},
store: new RedisStore(sessionOptions)
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.bodyParser());
app.use(express.csrf());
app.use(function(req, res, next) {
res.locals.token = req.session._csrf;
return next();
});
But now when I try to log in the CSRF token does not validate and I get a forbidden error. How can I make the session cookie secure AND use a CSRF token?
Here's what I use. I don't think you need the return before next(), but I'm not sure if that's your issue.
app
.set('view engine', 'jade')
.set('views', __dirname + '/../views')
.set('json spaces', 2)
.use(express.compress())
.use(express.cookieParser('our secret'))
.use(express.session({
store: new RedisStore({
port: config.redisPort,
host: config.redisHost,
db: config.redisDatabase,
pass: config.redisPassword
}),
proxy: true,
cookie: { httpOnly: true, secure: true }
}))
.use(express.bodyParser())
.use(express.methodOverride())
.use(express.csrf())
.use(function (req, res, next) {
res.cookie('XSRF-TOKEN', req.csrfToken());
res.locals.csrftoken = req.csrfToken();
next();
})
.use(everyauth.middleware());
The proxy: true is necessary for Heroku. Note that req.session._csrf has been obsoleted in the latest version of Express.

Categories