How can I use Node.js Express-session inside a conditional middleware? - node.js

var express = require('express')
var parseurl = require('parseurl')
var session = require('express-session')
var app = express()
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}))
This is my simple code. However, I want to use session only if the req.url contains /web. Is there a way I can wrap this inside a middleware of my own?
I've tried:
function setSession(req,res,next){
if(req.url.indexOf('/api') != 0){
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}));
next();
}else{
next();
}
};
and then
app.use(setSession);
But setting req.session.hello = "world" in my controller gives: TypeError: Cannot set property 'hello' of undefined. Simply put, it doesn't work. Are my arguments wrong in my middleware?

However, I want to use session only if the req.url contains /web. Is there a way I can wrap this inside a middleware of my own?
You certainly can. You can use express.Router to create sub-routes, like this:
var sessionMiddleware = session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
});
var webRoutes = express.Router()
.get('/', function(req, res, next) {
res.send('I have a session!');
});
var nonWebRoutes = express.Router()
.get('/', function(req, res, next) {
res.send('No session here');
});
app.use('/web', express.Router()
.use(sessionMiddleware)
.use(webRoutes));
app.use('/nonweb', nonWebRoutes);
Edit:
If however you want to conditionally execute the middleware function, you could do it like this:
app.use(function(req, res, next) {
if (req.url.indexOf('/api') !== 0) {
sessionMiddleware(req, res, next);
} else {
next();
}
});
app.get('/api', function(req, res, next) {
res.send(!!req.session); //false
});
app.get('/web', function(req, res, next) {
res.send(!!req.session); //true
});
But I prefer the sub-route approach because it maps your path route structure to a hierarchy which makes the code easier to read and easier to incorporate other middleware that make use of sessions, like passport.js for example.

Related

Issue: Node Express can't get session value with post request

I am developing a Shopify App in node.js. I am using different Shopify webhooks for different actions. similarly for a specific scenario I need to use session value while I am getting response from Shopify API. So in this scenario the session is not working for me. Please have a look on below code.
My code in index.js
const express = require('express');
const app = express();
var session = require('express-session');
app.set('trust proxy', 1); // trust first proxy
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: false,
secure: true,
maxAge: 60000
}
}));
//Set the session
app.get('/check_timewindow_orders', function (req, res, next) {
req.session.delvy_date = query.date_select;
});
app.use(function (req, res, next) {
res.locals.delvy_date = req.session.delvy_date;
next();
});
I get the session value in app.get and app.post.
app.get('/order_created_get', function (req, res) {
console.log(req.cookies.delDate);
// It display the value store in session.
});
But I cannot get the session value when I get the post from shopify Order Create Webhook API.
app.post('/order_created', function (req, res) {
console.log(req.cookies.delDate); // It display Null.
});
You are not actually using the session.
You need to add it as middleware:
app.get('/check_timewindow_orders', session, function(req, res, next){
req.session.delvy_date = req.query.date_select;
});
app.use(session, function(req, res, next) {
res.locals.delvy_date = req.session.delvy_date;
next();
});

Cookie value not changing express nodejs

I am using Express Framework and socket.io. I am working on authentication part and I am unable to change the value of cookie. Please see the code.
var session = require('express-session');
app.use(cookieParser());
app.use(session({
secret: "kvkjsdsbj12334",
resave:false,
saveUninitialized: false,
cookie:{
authStatus: "NotLoggedIn",
secure: false
},
rolling: true
}));
app.use(function (req, res, next){
console.log(req.session.cookie.authStatus); // Logs NotLoggedIn after /login.
});
app.post('/login',(req,res)=>{
var body = _.pick(req.body,['email','password']);
var email = body.email;
var password = body.password;
Users.findByCredentials(body.email,body.password).then((user)=>{
req.session.user = user;
req.session.cookie.authStatus = "loggedIn";
req.session.save();
//Redirected from here
});
});

Why index.html is rendered in Node.js

I have a handler for '/', which redirects to /login.html.
However, even though i'm explicitly calling to redirection, the page that is rendered is STILL index.html.
it's pretty lame behaviour, since I'm expecting A and gets B.
How can I solve it?
var app = express();
app.use(express.static('public'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());
MW:
app.use('/', (req, res, next) => {
if (req.user) {
next();
} else {
res.redirect('/login.html');
}
});
app.post('/login',
passport.authenticate('local', {
successRedirect: '/index.html',
failureRedirect: '/login.html'
})
);

Passport authentication not work for one specific route with express router

I'm trying to access 'testpage' route. But the req.isAuthenticated() returns false only for this route. (This route was there before I started to add authentication).
I'm able to go to login page and authenticate with google. Then I can access 'signup' or 'user_profile' route without problems.
After login if I try:
localhost:8080/testpage
the server sends me to "/". But if I try:
localhost:8080/testpage#
with hash sign in the end, the page is rendered.
// routes/users.js
var express = require('express');
var router = express.Router();
module.exports = function (passport) {
router.get('/login', function (req, res) {
res.render('login', { message: req.flash('loginMessage') });
});
router.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
router.get('/auth/google/callback',
passport.authenticate('google', {
successRedirect: '/',
failureRedirect: '/'
}));
router.get('/user_profile', isLoggedIn, function (req, res) {
res.render('user_profile');
});
router.get('/signup', isLoggedIn, function (req, res) {
res.render('signup');
});
router.get('/testpage', isLoggedIn, function (req, res) {
res.render('testpage');
});
return router;
};
function isLoggedIn(req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
Any ideas why this is happening?
* update *
Here my 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 passport = require('passport');
var flash = require('connect-flash');
var session = require('express-session');
var db = require('./mongoose');
var app = express();
require('./config/passport')(passport);
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
secret: 'secret123',
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
var users = require('./routes/users')(passport);
app.use('/', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// 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;
It could be due to the express-session middleware that is needed for passport. you can fix it by using middleware in following order.
var session = require('express-session')
var app = express()
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret: 'yoursecret',
resave: true,
saveUninitialized: true,
cookie: { secure: true },
// you can store your sessions in mongo or in mysql or redis where ever you want.
store: new MongoStore({
url: "mongourl",
collection: 'sessions' // collection in mongo where sessions are to be saved
})
}))
// Init passport
app.use(passport.initialize());
// persistent login sessions
app.use(passport.session());
See https://github.com/expressjs/session for more details.
Also I think so you have not config google strategy.
try some thing like following
var GoogleStrategy = require('passport-google-oauth').OAuthStrategy;
// Use the GoogleStrategy within Passport.
// Strategies in passport require a `verify` function, which accept
// credentials (in this case, a token, tokenSecret, and Google profile), and
// invoke a callback with a user object.
passport.use(new GoogleStrategy({
consumerKey: GOOGLE_CONSUMER_KEY,
consumerSecret: GOOGLE_CONSUMER_SECRET,
callbackURL: "http://www.example.com/auth/google/callback"
},
function(token, tokenSecret, profile, done) {
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return done(err, user);
});
}));
Finally after one entire day I just realized that when I was typing localhost:8000/testpage in the url bar it was been changed to www.localhost:8000/testpage. And the auth dos not work with www*. Another thing is that google chrome tries to predict what url you will type and this could cause this type of error, and it is annoying at debugging. So I unchecked this options at chrome's settings, preventing prediction.

Node.js session login

Node.js does not seem to be remembering my session.
I am using Express with cookie-parser and express-session as middleware.
In my application, I use Mongo to keep usernames and passwords.
The following is a MWE:
var express = require('express');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var app = express();
app.use(cookieParser({
secret: 'derma-aid'
}));
app.use(session({
secret: 'derma-aid',
resave: false,
saveUninitialized: false,
cookie: {secure: false}
}));
// CORS (Cross-Origin Resource Sharing) headers to support Cross-site HTTP requests
app.all('*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'X-Requested-With');
next();
});
app.get('/login', function(req, res)
{
console.log('login');
req.session.user_id = 500;
res.send('<h1>login</h1>');
});
app.get('/view', function(req, res)
{
console.log('view id: ' + req.session.user_id);
res.send('<h1>view: ' + req.session.user_id + '</h1>');
});
app.get('/logout', function(req, res)
{
console.log('logout: ' + req.session.user_id);
res.send('<h1>logout: ' + req.session.user_id + '</h1>');
delete req.session.user_id;
});
app.listen(5000);
If you go to the browser to http://localhost:5000/login, then req.session.user_id should be set and displayed correctly on http://localhost:5000/view.
But, instead, I am getting undefined messages...
EDIT: cookie: {secure: false} as suggested by #tiblu. I get this error: TypeError: Secret string must be provided..
I managed to fix the TypeError: Secret string must be provided.
- app.use(cookieParser({
- secret: 'derma-aid'
- }));
+ app.use(cookieParser(
+ 'derma-aid'
+ ));
In your session middleware setup change from:
cookie: {secure: true}
to
cookie: {secure: false}
Cookies marked as secure are not sent for NON-HTTPS requests. You are accessing your application over HTTP.
More reading on that https://en.wikipedia.org/wiki/HTTP_cookie#Secure_cookie

Resources