Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Cannot retrieve session data stored in prior request #32

Closed
YukiThornton opened this issue Jan 29, 2018 · 7 comments
Closed

Cannot retrieve session data stored in prior request #32

YukiThornton opened this issue Jan 29, 2018 · 7 comments

Comments

@YukiThornton
Copy link

Hi.
My team is struggling to implement csrf tokens to our express APIs and run tests correctly.
Our app works well on real browsers, but the tests related with sessions fail.
We added csrf secret to session in GET request, but we cannot retrieve the secret in subsequent POST request.
We're trying to figure out whether we're using supertest-session in a wrong way, or something unexpected is happening (ex. some other Express middlewares interfere the test code).
We also want to know how to access session objects in test code to debug more closely.
We'd appreciate any help!

  • Problem

    • When we run the test , req.session._csrf in router.post('/login') is undefined
      • _csrf key is added to req.session in router.get('/login').
  • Test code

    var request = require('supertest'),
    var app = require('../../app');
    var session;
    var testSession = null;

    before(function(done) {
      session = require('supertest-session');
      testSession = session(app);
      testSession.get('/login')
        .end(function(err, res) {
          if (err) {
            console.log(err);
          }
          cookie = res.headers['set-cookie'];

          testSession.post('/login')
            .type('form')
            .set('cookie', cookie)
            .send({username: 'xxxxxxx'})
            .send({password: 'xxxxxxx'})
            .end(function(err, res) {
              if (err) {
                console.log(err);
              }
            });
        });
    });
  • Source code
router.get('/login',
  function(req, res, next) {
    var secret = tokens.secretSync();
    var token = tokens.create(secret);

    req.session._csrf = secret;
    res.cookie("_csrf", token);
    res.render('login', {error: req.flash('error')});
  }
);

router.post('/login', function(req, res, next) {
  var secret = req.session._csrf;
  var token = req.cookies._csrf;
  console.log(secret);  // undefined
  console.log(token);

  if (tokens.verify(secret, token) === false) {
    return next(new Error("Invalid Token"));
  }

  // authenticate user
});
@rjz
Copy link
Owner

rjz commented Jan 29, 2018

Hey, @okunoyuki!

Regarding test state, any cookies held by the session should be available from testSession.cookies (see e.g. this test). supertest-session is meant to handle cookie-based sessions transparently; if that's broken, there's a bug.

As far as the problem here, I'm not sure exactly what's up. When you have a moment, could you provide a few more details about the implementation and behavior you're seeing?

  1. what middleware is the app using for session management?
  2. if you log out res.headers after calling GET /login in the test setup, the _csrf cookie should be present. Is a session cookie (if expected) present as well? And if so, does it (or its backing datastore) contain the expected values?
  3. finally, if the cookies sent from the app look correct, are they also present in testSession.cookies?

Thanks in advance!

@YukiThornton
Copy link
Author

Thank you for your quick and kind reply! @rjz
I didn't know about testSession.cookies but that sounds convenient!

Looks like we use multiple session-related frameworks(express-session and passport). Maybe we shouldn't use both of them at a time?

var passport = require('passport');
app.use(require('express-session')({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
app.use(passport.session());

For 2, the _csrf cookie exists in res.headers after calling GET /login (The following is the output that I got). I assume that I can access 'session cookie' using supertest-session(I apologize if it's a totally wrong assumption), but I don't know how. Could you show me how to access session?

{ 'cache-control': 'private,no-store,no-cache,must-revalidate,proxy-revalidate',
  pragma: 'no-cache',
  'set-cookie': 
   [ '_csrf=XXXXXXXXXXXXXXXXXXXXXXXXXX; Path=/',
     'connect.sid=YYYYYYYYYYYYYYYYYYYYYYY; Path=/; HttpOnly' ],
  'content-type': 'text/html; charset=utf-8',
  'content-length': '1394',
  etag: 'W/"572-LEgv480pG9D7SI5tj94/Zg"',
  date: 'Mon, 29 Jan 2018 23:36:59 GMT',
  connection: 'close' }

For 3, testSession.cookies had _csrf cookie with expected values.

@rjz
Copy link
Owner

rjz commented Jan 30, 2018

Got it—thanks, @okunoyuki!

Depending on what backing store you are using with express-session, it may not be possible (or desirable) to peek into the session from outside the app. But I think we may be able to make this work from the outside.

First thought: since supertest-session will echo any cookies it receives, try dropping .send('cookie', ...) from the test setup:

testSession.get('/login')
  .end(function(err, res) {
    if (err) {
      return done(err);
    }

    testSession.post('/login')
      .type('form')
      .send({
        username: 'xxxxxxxx',
        password: 'xxxxxxxx',
      })
      .end(done);
  });

It looks like the session cookie is being attached correctly (you can see it in the HTTP requests, and it should appear in testSession.cookies['connect.sid'] after the initial request). The next thought, then, would be to make sure the session is being restored correctly inside the app. If you log out req.cookies in the post routes, the connect.sid cookie should match the cookie seen inside the tests. If it doesn't, it's possible that something is missing in the express-session configuration.

@YukiThornton
Copy link
Author

Thank you! @rjz
I'm sorry I was pretty busy this week and haven't tried you ideas yet.
I'll try them and get back to you next week!

@YukiThornton
Copy link
Author

@rjz
Thank you for your advice!
It worked without .send('cookie', ...). And I found out that there is something wrong with express-session configuration since the connect.sid cookie in the post routes didn't match the one inside the tests.
Since my problem doesn't seem relevant to supertest-session for now, you can close this issue. Thank you so much!

@rjz
Copy link
Owner

rjz commented Feb 7, 2018

Awesome, @okunoyuki, I'm glad to hear that it's working!

Please do be in touch if you run into any other issues.

@rjz rjz closed this as completed Feb 7, 2018
@ahmadbingulzar
Copy link

ahmadbingulzar commented Oct 27, 2022

having the same issue
getting XSRF-TOKEN successfully but when i try to login it shows XSRF-TOKEN mismatch also it is working preety fine on browsers and postman

`const app = require('../../../app.js');
const expect = require('chai').expect;
const request = require('supertest');
var csrfToken;

describe('GET /api/csrf-token', () => {
it('OK, Getting CSRF Token', (done) => {
request(app).get('/api/csrf-token')
.expect(200)
.then((res) => {
const body = res.body;
csrfToken=body.csrfToken;
expect(body).to.contain.property('csrfToken');
done();
})
.catch((err) => done(err));
});
});

describe('POST /api/users/login', () => {
it('OK, Logging in with super admin crediantials', (done) => {
request(app).post('/api/users/login')
.set('Content-Type', 'application/json')
.set("Accept","/")
.set("XSRF-TOKEN",csrfToken)
.set("Cookie","XSRF-TOKEN",csrfToken)
.set("withCredentials",true)
.expect(200)
.send({"email":"super@abc.com","password":"abc"})
.expect((res) => {
const body = res.body;
console.log(body);
expect(body.message).to.contain.property('Auth Successful');
expect(body).to.contain.property('token');
done();
})
.catch((err) => done(err));
});
});
`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants