Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

In Express Session Every Time new session id is generated on ajax call #520

Closed
brijeshIOGit opened this issue Oct 30, 2017 · 18 comments
Closed
Labels

Comments

@brijeshIOGit
Copy link

brijeshIOGit commented Oct 30, 2017

I am Using expression-session and express-mysql-session for storing in database but on every ajax returns new session id.For more info calling from http only.This issue is not coming when i disable security of browser.``

My Code is

var express = require('express');
var mysql = require('mysql');
var jwt = require('jsonwebtoken');
var session=require('express-session');
var MySQLStore = require('express-mysql-session')(session);

var options = {
    host: 'localhost',// Host name for database connection.
    port: 3306,// Port number for database connection.
    user: 'root',// Database user.
    password: '',// Password for the above database user.
    database: 'node',// Database name.
    checkExpirationInterval: 900000,// How frequently expired sessions will be cleared; milliseconds.
    expiration: 1512671400000,// The maximum age of a valid session; milliseconds.
    createDatabaseTable: true,// Whether or not to create the sessions database table, if one does not already exist.
    connectionLimit: 10,// Number of connections when creating a connection pool
    schema: {
        tableName: 'sessions',
        columnNames: {
            session_id: 'session_id',
            expires: 'expires',
            data: 'data'
        }
    }
};

var connection = mysql.createConnection(options); // or mysql.createPool(options);
var sessionStore = new MySQLStore({}/* session store options */, connection);
var router = express.Router();

router.use(session({
    name: 'session_cookie_name',
    secret: 'session_cookie_secret',
    store: sessionStore,
    resave: false,
    saveUninitialized: true,
    cookie: { path: '/', httpOnly: false, secure: false, maxAge: 365 * 24 * 60 * 60 * 1000 }
}));

router.get('/session', function(req, res, next) {
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    res.send(req.sessionID);
});
@brijeshIOGit brijeshIOGit changed the title Every Time new session id is generated on ajax call In Express Session Every Time new session id is generated on ajax call Oct 31, 2017
@dougwilson
Copy link
Contributor

Hi @brijeshIOGit sorry your issue hasn't gotten to yet. Thanks for the server code! Is it possible you can provide the client side code that demonstrates the issue? Nothing seems wrong in your server example, so not sure what is happening. Ideally can you provide the following:

  1. Version of Node.js
  2. Version of this module and the others used in your code above
  3. Complete client-side code that reproduces the issue
  4. Instructions for how to set it all up and the step by step instructions to reproduce the issue.

Thanks!

@brijeshIOGit
Copy link
Author

brijeshIOGit commented Jan 16, 2018 via email

@dougwilson
Copy link
Contributor

Hi @brijeshIOGit I use this module on my own servers and of course use AJAX calls to the server (because, single page apps) and never have an issue. I'm not really sure what is going on with your setup, through. I'd be happy to take a look 👍 Ideally can you provide the following:

  1. Version of Node.js
  2. Version of this module and the others used in your code above
  3. Complete client-side code that reproduces the issue
  4. Instructions for how to set it all up and the step by step instructions to reproduce the issue.

Thanks!

@naz-mul
Copy link

naz-mul commented Jan 29, 2018

@dougwilson I have the same issue from my AngularJS client. I am running my server with Node v6.11.3, express-session 1.15.6

@dougwilson
Copy link
Contributor

Hi @naz-mul very sorry you're experiencing this issue :( No one has provided me the information I need to start looking into it yet. Would you be able to? I would love to get to the bottom of this 👍

@ricfernandes
Copy link

ricfernandes commented Jan 30, 2018

Hi,

I have been facing this issue for quite a long time now and it has had me stumped,following are more details:

NodeJS 4.5
express-session: 1.12.1
Session store for express-session : Memory
Authentication into application is via SSO (Ping)

To check if the user is logged in we have the following common check executed on each route of the application:

Server code:

if(req.session.somekey1 || req.session.somekey2){
//user is considered to be logged in
}

else{
//user session hasn't been set, hence force to logout page
if (req.headers["x-requested-with"] == 'XMLHttpRequest')
 {
   res.send({error:"session expired", code:1111});
 }
}

Here is the flow of the issue

  1. User is logged in successfully
  2. User keeps the application idle in the browser for over an hour OR hibernates the machine
  3. User tries to hit a URL after one hour OR much later in the day the user is redirected to the login page as the session timeout at Node server application is set to one hour
  4. Here the SSO login is re-triggered (we trigger this on the /# page)
  5. User is successfully logged in again
  6. The session check on the initial landing page after login, that is, /dashboard is successful
  7. However in the AJAX call that executes from /dashboard the session check fails and hence we force a logout and user lands on /loggedoutpage
  8. Here there is a link to login again and triggers SSO

Steps 4 to 8 continue in a loop when the user tries to login again.
The only way to stop this is to close the browser completely, clear cookies and start it up again

Note that on the forced logout at step 7 below is the code:

router.get('/applogout', function(req,res,next){
    res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');
    req.session.destroy();
    req.logout();
    res.redirect('/loggedout');
});

Following is the client side code of how we are forcing the logout on AJAX call

$.ajaxSetup({
	complete: function (x, status, error) {
		if(x.status==403){
			alertify.error("You are not authorized to perform this action.");
		}
		else if(x.status==500){
			alertify.error("An exception occurred during processing.");
		}
		else if (x && x.responseJSON) {
			if (x.responseJSON.code === 1111 && !ajaxTriggeredLogout) {
				ajaxTriggeredLogout = true;
				alertify.error("Sorry, your session has expired. You will be logged out shortly");
				setTimeout(function(){window.location.href = "/applogout"}, 2000);
			}
		}
		else if (x && x.responseText && x.responseText.indexOf('"code":1111') >= 0 && !ajaxTriggeredLogout) {
			ajaxTriggeredLogout = true;
			alertify.error("Sorry, your session has expired. You will be logged out shortly");
			setTimeout(function(){window.location.href = "/applogout"}, 2000);
		}
		else if (status === 'timeout') {
			alertify.error("Connection Timed Out");  
		}
	},
	timeout: 60000
});

From analysis it seems to be related to a possible race condition because Memory store is being used for the session but haven't been able to confirm this nor find a resolution for it

Any help here is appreciated

@dougwilson
Copy link
Contributor

Hi @ricfernandes thanks for the additional information. I'm trying to setup a server and client what that code but not sure how to get it pieced together to be functional in order to be able to run it with a debugger to help see what is going on. Can you provide instructions for how to set it all up and the step by step instructions to reproduce the issue?

@ricfernandes
Copy link

Hi @dougwilson ,

Apologies for the long wait, following is a sample skeleton of the code for the usecase:
https://www.dropbox.com/s/4qo44l7du902fwh/ExpressSessionIssue.zip?dl=0

  1. You can access http://localhos:5600/# and will get loggedin and redirected to http://localhos:5600/nk

  2. There is a link on the page to execute an AJAX call for the test

The steps for the issue are mentioned in my previous post, the only difference is the login with SSO is replaced by a simulation of it with user just getting logged in on hitting /#

Hopefully this will help

Thanks
Richard

@ricfernandes
Copy link

Hi @dougwilson ,

Just wanted to check if you have had a chance to test out the sample code provided.

Thanks
Richard

@dougwilson
Copy link
Contributor

I haven't yet, very sorry. I have it on my todo unless someone else is able to figure it out before hand.

@dougwilson
Copy link
Contributor

Ok, so I just downloaded, installed, and setup the app. I loaded the /# and clicked on the AJAX link. Everything seems good. Didn't realize that I actually needed to do this were I would have at least an hour to reproduce the issue (and then an hour each time to try again...?) so I didn't choose a good time, so if I really need to keep it open for an hour, I may not be able to have it left open that long during this session.

@dougwilson
Copy link
Contributor

I can say, though, that looking at the cookie that your server set in the web browser, it is set to expire after 1 hour. So... is this your issue? Once the cookie expires, the web browser won't sent in in the request, so if you just leave the app past the cookie expiration time, you'll get a new session.

@ricfernandes
Copy link

@dougwilson , yes the cookie is set to expire after an hour. Adding back the steps sed to reproduce this for reference:

  1. User is logged in successfully
  2. User keeps the application idle in the browser for over an hour OR hibernates the machine
  3. User tries to hit a URL after one hour OR much later in the day the user is redirected to the login page as the session timeout at Node server application is set to one hour
  4. Here the SSO login is re-triggered (we trigger this on the /# page)
  5. User is successfully logged in again
  6. The session check on the initial landing page after login, that is, /dashboard is successful
  7. However in the AJAX call that executes from /dashboard the session check fails and hence we force a logout and user lands on /loggedoutpage
  8. Here there is a link to login again and triggers SSO

Steps 4 to 8 continue in a loop when the user tries to login again.
The only way to stop this is to close the browser completely, clear cookies and start it up again

As noted in step 6, after the re-login the first landing page does not have any issue with verifying that the session is active and loads successfully. however the AJAX request that is triggered from the landing page is not able to detect the same session, in fact it ends up with a different session id

@dougwilson
Copy link
Contributor

Thanks for the information! I'll try to start this again sometime this week or next if I know I have at least an hour to spend on it, though I have no guarantees. Absolutely would accept a PR with a fix; though 👍

@ottis
Copy link

ottis commented Jun 15, 2018

@ricfernandes / @dougwilson did either of you get any further with this? I'm hitting the same issue:

Node version: v8.11.3
express-session: ^1.15.6

client side code

fetch('/api/test')
  .then(resp => resp.json())
  .then(res => {
    console.log(res);
  });

fetch('/api/test2')
  .then(resp => resp.json())
  .then(res => {
    console.log(res);
  });

server side

app.use(session({
  secret: 'keyboard cat',
  resave: true,
  saveUninitialized: false,
  cookie: {
    maxAge: 3600000
  }
}));

app.get('/api/test', (req, res) => {
  console.log('TEST: ', req.sessionID);
});

app.get('/api/test2', (req, res) => {
  console.log('TEST2: ', req.sessionID);
});

output

TEST: UV2UwbDwcobDEhv0E4SNUyR2ldYyzu8C
TEST2: Ab6ReF4PUZFazCMDQwhWAweuMwPY1tSa

@dougwilson
Copy link
Contributor

I'm sorry I have not and honestly completely forgot about this. I'll try to find some time, but ultimately the best way to get moving is if you're able to make a pull request with a fix, of course ❤️

@ottis
Copy link

ottis commented Jun 15, 2018

Actually (for my situation at least) I've come across a solution for this right after I posted lol updated below:

fetch('/api/test', {
  credentials: "same-origin"
})
  .then(resp => resp.json())
  .then(res => {
    console.log(res);
  });

So (with fetch at least) it doesn't send cookies by default, you need to set credentials to "same-origin". This kicks the express-session into gear to use the correct session for the request. @brijeshIOGit / @ricfernandes not sure if this helps? Maybe double check the request is actually sending the HTTP cookie header.

@dougwilson
Copy link
Contributor

Thanks @ottis ! I'm going to close this since we have a solution 🎉

@expressjs expressjs deleted a comment from murphman300 Jul 31, 2019
@expressjs expressjs locked as resolved and limited conversation to collaborators Jul 31, 2019
# for free to subscribe to this conversation on GitHub. Already have an account? #.
Labels
Projects
None yet
Development

No branches or pull requests

5 participants