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

Created on 30 Oct 2017  路  18Comments  路  Source: expressjs/session

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);
});
question

Most helpful comment

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.

All 18 comments

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!

Any ajax call from from front end to session api will create new session id. You can check by hitting session api using ajax call.You will the exact problem if you print the session ID returned by api.

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!

@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

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 馃憤

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 /login 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

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?

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/login 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 /login

Hopefully this will help

Thanks
Richard

Hi @dougwilson ,

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

Thanks
Richard

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

Ok, so I just downloaded, installed, and setup the app. I loaded the /login 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.

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.

@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 /login 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

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 :+1:

@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

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 鉂わ笍

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.

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

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Matthew-Christopher picture Matthew-Christopher  路  27Comments

skoranga picture skoranga  路  30Comments

aheyer picture aheyer  路  15Comments

renehauck picture renehauck  路  16Comments

rukshn picture rukshn  路  20Comments