Sending cookies to browser fails in Express - node.js

I am able to successfully create my cookies and I can clearly see them in my console. Now the problem is that I want to send those cookies to the browser and I am not able to do that. When I open my Chrome and go to cookies they are not present there
I have set the secure option to false and also httponly to false but it does not seem to work
req.session.cart = cart;
var cookieValue = JSON.stringify([req.session.cart],{secure:false, maxAge: 180 * 60 * 1000, httpOnly: false });
var cookie = req.cookies.cookieName;
// no: set a new cookie
res.cookie('cookieName',cookieValue);
console.log('cookie created successfully');
// yes, cookie was already present
console.log('cookie exists', cookieValue);
res.redirect('/');
When I create the cookie they must appear in the browser

Like #Mike 'Pomax' Kamermans mentioned, I think this may have to do with res.redirect. Try adding them to your / route as well. Something like this:
// Requires cookie-parser
// https://expressjs.com/en/api.html#req.cookies
// https://github.com/expressjs/cookie-parser
app.post('/cart', function(req, res){
req.session.cart = cart;
var cookieValue = JSON.stringify([req.session.cart],{secure:false, maxAge: 180 * 60 * 1000, httpOnly: false });
var cookie = req.cookies.cookieName;
if(!cookie) {
res.cookie('cookieName',cookieValue);
console.log('cookie created successfully');
} else {
console.log('cookie exists', cookieValue);
}
res.redirect('/');
});
app.get('/', function(req, res){
if((typeof req.cookies == "object")&&(Object.keys(req.cookies).length>0)) {
console.log("Cookies are present");
// copy cookies from req to res
for(var o=0; o<Object.keys(req.cookies).length; o++) {
var key = Object.keys(req.cookies)[o];
res.cookie(key,req.cookies[key]);
}
}
res.status(200).send("OK");
});

Related

How to only allow one user connection alive at the same time with Nodejs and Expressjs?

I just need to manage the concurrence on my app built with nodejs on the top of the nestjs framework.
As a far as I know, the most simplest way to do that is controlling that online one session user in expressjs is alive.
I am not taking care about security or whatever other issues, just want to know how many users are connected and restricting it to only one user session till its session is expired.
Here is my codebase
var express = require('express');
var session = require('express-session');
var app = express();
var numConnections = 0;
app.use(session({
cookieName: 'sessionTest',
secret: 'eg[isfd-8yF9-7w2315df{}+Ijsli;;to8',
cookie: {
secure: false,
maxAge: 1000 * 10,
sameSite: true
}
}));
app.use((req, res, next) => {
console.log(req.session.store)
console.log(req.session.ip)
console.log(req.session.useragent)
console.log(req.connection.remoteAddress)
console.log(req.headers['user-agent'])
if (numConnections === 0
// && req.session
) {
req.session.ip = req.connection.remoteAddress;
req.session.useragent = req.headers['user-agent'];
req.session.page_views = 1;
res.send("Welcome to this page for the first time!");
numConnections++;
console.log(req.session);
next();
}
else if (numConnections == 1 &&
req.session.ip === req.connection.remoteAddress
&& req.session.useragent === req.headers['user-agent']
) {
req.session.page_views++;
res.send("You visited this page " + req.session.page_views + " times");
console.log('TEST');
next();
} else {
console.log('There is someone using the app!!!');
return res.sendStatus(401);
}
})
app.listen(3001);
I really appreciate if someone can help me
You could use the store to retrieve the current amount of open sessions. The doc says stores may implement length and/or all methods. However, it appears that only the default MemoryStore handles these. You can look at all the compatible store implementations at the bottom of the page and pick the one that fits your environment.
It probably (i.e. not tested) looks like this:
var session = require('express-session');
var memoryStoreThatWillBeChangedBeforeLiveEnvironment = new MemoryStore();
...
app.use(session({
...
store: memoryStoreThatWillBeChangedBeforeLiveEnvironment
}));
app.use((req, res, next) => {
memoryStoreThatWillBeChangedBeforeLiveEnvironment.length((err, size) => {
if (err) return res.status(418).send("I'm a teapot");
var numConnections = size;
// call your code here
})
});
(Quite obviously, if an implementation only offers the all method, you can count the returned array of sessions.)

Force share.js use the same express session data

I have a simple express app that use session middleware together with passport-local middleware. Then I use share.js with browserchannel to stream data to server via share.listen(stream). All in align with documentation here.
My problem is that I cannot access session data (modified by passport-local and containing userID that was logged in) within stream. I need it to be able to restrict/grant access within client.on('message', function(data) {..}); based on some logic, but what of first importance is to check that the message came from logged in user. There, if I try to read ID it will be different from what potencialy is inside req.user._id. It seems that there share.js or browserchannel uses some different session, maybe?..
Here's the code:
var app = express();
var express = require('express');
...
// SETUP AND INIT
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true,
limit: 1024 * 1024 * 10
}));
app.use(methodOverride());
app.use(session({
secret: global.CONFIG.session.secret,
maxAge: new Date(Date.now() + 1000 * 60 * 60 * 24 * 2),
store: new MongoStore(global.CONFIG.mongo),
resave: true,
saveUninitialized: true
}));
app.use(express.static(__dirname + '/build'));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
// Create the sharejs server instance.
var backend = livedb.client(livedbMongo(global.CONFIG.mongo.url, false));
var share = sharejs.server.createClient({
db: backend
});
app.use(browserChannel(function(client) {
var stream = new Duplex({objectMode: true});
stream._write = function(chunk, encoding, callback) {
if (client.state !== 'closed') {
client.send(chunk);
}
callback();
};
stream._read = function() {
};
stream.headers = client.headers;
stream.remoteAddress = stream.address;
client.on('message', function(data) {
console.log(client.id) // <- I wish it was the same as in req.user._id..
stream.push(data);
});
stream.on('error', function(msg) {
client.stop();
});
client.on('close', function(reason) {
stream.emit('close');
stream.emit('end');
stream.end();
});
// Actually pass the stream to ShareJS
share.listen(stream);
}));
It seems to me, from looking at the code, that there might be a solution that won't require hacking the module:
var browserChannel = require('browserchannel').server;
var middleware = browserChannel(options, function(session, req) {
if (req.user) {
session.user = req.user;
}
});
app.use(middleware);
See here.
I have the same problem and I solved it by wrapping the browserchannel middleware constructor in a custom constructor:
function myMiddlewareConstructor () {
var request;
var bcMiddleware = browserChannel(function (client) {
//here you see the request
});
return function (req,res,next) {
request = req;
bcMiddleware(req,res,next);
}
}
app.use(myMiddlewareConstructor());
It avoids having to change the browserchannel code.
After several days of inspecting the code I have found a solution. If we look at this line in browserchannel/dist/server.js we can see that the session is being created using some information from initial request. We can modify this part of code by adding
session = createSession(req.connection.remoteAddress, query, req.headers);
// ----------- we add this ------------
session.user = {};
if( req.user )
session.user = req.user;
// ------------------------------------
This will add user session details from initial request to the session variable.

Node.Js + express + Passport : Can't logout user

I wrote a JS script for a webserver that includes authentication using the passport and the digest strategy. I am not using sessions, but I have tried using sessions and it does not change the results. The browser requests the "/login" route and displays a built-in login dialog. Authentication works fine, but I can't get the user to "logout." The problem seems to be that the browser remembers the login credentials and resends them automatically. The end result is that the user must close the browser completely to log out, but that is a problem for this application. I know that there must be a way to tell the browser not to do this, but I haven't figured it out.
I figured out a hack to get the browser to display the login dialog again; force the authentication function to return a false. However, I haven't figured out a way to do this per-session. Right now, if one person logs out, everyone gets logged out. It's not a workable solution.
Can anyone tell me what I'm doing wrong here? One thing I'm wondering is whether I'm returning the proper response to the browser when it POSTs to the /logout route (see end). I return res.json(""), but maybe there's a different response I should send to tell the browser to forget the credentials for the session?
My code follows. Any insight is greatly appreciated. Thank you in advance.
T
var passport = require('passport'),
DigestStrategy = require('passport-http').DigestStrategy;
var express = require('express');
var app = express();
app.configure(function () {
app.use(
"/", //the URL throught which you want to access to you static content
express.static('./www') //where your static content is located in your filesystem
);
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.session({ secret: 'keep moving forward' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
});
app.listen(80); //the port you want to use
/**
* CORS support.
*/
app.all('*', function(req, res, next){
if (!req.get('Origin')) return next();
// use "*" here to accept any origin
// For specific domain, do similar: http://localhost'
// Use an array for multiple domains, like [http://localhost', 'http://example.com' ]
res.set('Access-Control-Allow-Origin', '*' );
res.set('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
res.set('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Authorization');
next();
});
//
// Configure passport authentication
//
// Used to force the browser to display the login screen again.
var forceLogin = false;
passport.use(new DigestStrategy({ qop: 'auth' },
function(username, done ) {
if ( !forceLogin )
{
return done(null, username, "nimda");
}
else
{
//
// Forces the browser to request the user name again by returning a failure to its last request.
//
console.log ( "forcing user to log in" );
forceLogin = false;
return done(null, false);
}
));
passport.serializeUser(function(user, done) {
console.log( "serialize user " + user.toString() );
done(null, user.toString());
});
passport.deserializeUser(function(id, done) {
console.log( "deserialize user " + id.toString() );
done(null, id);
});
app.post('/login', passport.authenticate('digest', { session: true }),
function(req, res) {
console.log( "/login");
res.header('Cache-Control', 'no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0');
res.json({ id: req.user.id, username: req.user.username });
});
app.post('/logout', function(req, res){
req.logOut();
// NOTE: Same results as req.logout
//
// req.session.destroy(function (err) {
// res.redirect('/');
// });
res.redirect("/");
// flag to force a login
forceLogin = true;
console.log( "logout");
// Is this the proper return to the browser?
return res.json("");
});
You could try the following
req.session.destroy()
req.logout()
res.redirect('/')
Saving the new state of the session is important if you're using some form a session store for persistent sessions (eg. Redis). I tried the above code with a similar setup and it seems to work for me
Server needs somehow notify web browser that he need to refresh login info (MD5 digests).
For that you can send 401 error code and usually browser will show login popup message.
By the way, all these tricks with sessions are useless because browser already have all required info for automatic logging in.
So you can try next code:
req.logout();
res.send("logged out", 401);
A bit late to the party, but I found this thread on Google while searching for answer and nothing worked for me. Finally, I was able to solve it so thought I could post solution here for anyone that might read this in the future.
So basically, I use node.js, express, passport(local) and rethinkdb as my storage, and I was having problem with req.logout(); not logging me out.
My setup:
var express = require( 'express' );
var passport = require( 'passport' );
var session = require( 'express-session' );
var RDBStore = require( 'express-session-rethinkdb' )( session );
I tried a lot of stuff and nothing was working, so finally I decided to manually do it, by removing session record from database myself.
Here is the code I used:
app.get( '/logout', function ( req, res, next ) {
if ( req.isUnauthenticated() ) {
// you are not even logged in, wtf
res.redirect( '/' );
return;
}
var sessionCookie = req.cookies['connect.sid'];
if ( ! sessionCookie ) {
// nothing to do here
res.redirect( '/' );
return;
}
var sessionId = sessionCookie.split( '.' )[0].replace( 's:', '' );
thinky.r.db( 'test' ).table( 'session' ).get( sessionId ).delete().run().then( function( result ) {
if ( ! result.deleted ) {
// we did not manage to find session for this user
res.redirect( '/' );
return;
}
req.logout();
res.redirect( '/' );
return;
});
});
So I hope this helps someone :)
res.redirect('/') will end the response, you can not call subsequently write(), end(), send(), json() ...etc
Just like this:
app.post('/logout', function(req, res){
req.logOut();
res.redirect("/");
});
deserializeUser should return a user instead of id:
passport.deserializeUser(function(id, done) {
findUser(id, function(err, user) {
if(err) {
done(err)
} else {
done(null, user);
}
}
});
I have taken a short discussion, I realize that digest username/password store on browser (not on server), so req.logout not help, there no way to clear it from server. You just close browser and open again that mean logout.
You can use a variable in cookie or session to mark the session as logout, but I think we should not do not, because username/password still in browser.
It's digest!

How to access express.session.MemoryStore via socket.io objects?

I am doing this in a login function
app.post('/teacherlogin', function(request, response) {
var username = request.body.username;
var password = request.body.password;
con.query('SELECT t_id from login_teacher where username="'+username+'" and password="'+password+'"',function(err,results){
if(results.length > 0) {
request.session.regenerate(function(){
request.session.user = username;
request.session.type = 'teacher';
request.session.id = results[0].t_id;
response.redirect('/teacherhome');
});
} else {
response.redirect('teacherlogin');
}
});
});
now I want to emit the 'id' and 'type' I have stored to the session object. How should I do this? I have read this article but being inexperienced I am facing difficulty in using it. I have used it in my code
var MemoryStore = express.session.MemoryStore;
var sessionStore = new MemoryStore();
app.use(express.bodyParser());
app.use(express.cookieParser('secret text'));
app.use(express.session({
store: sessionStore,
secret: 'secret',
key: 'express.sid'}
));
and
var Session = require('connect').middleware.session.Session;
io.set('authorization', function (data, accept) {
if (data.headers.cookie) {
data.cookie = require('cookie').parse(data.headers.cookie);
data.sessionID = data.cookie['express.sid'].split('.')[0];
console.log('data.sessionID "'+data.sessionID);
data.sessionStore = sessionStore;
sessionStore.get(data.sessionID, function (err, session) {
if (err || !session) {
accept('Error', false);
} else {
data.session = new Session(data, session);
accept(null, true);
}
});
} else {
return accept('No cookie transmitted.', false);
}
});
I am not getting any thing in the session object. I tried to log the contents of the sessionStore and it seems to be empty! Does that mean the information I am storing in the session isn't being stored in the sessionStore? If yes, what should I do to store it there? and if it is stored there why isn't the sessionStore.get function unable to find it?
I am not sure if you're still working on this, but you can access session data with just a MemoryStore. After all how else would Express use it if it didn't work? :)
A simple way to demonstrate MemoryStore working is this:
var express = require("express")
, app = express()
, sessionStore = new express.session.MemoryStore();
// middleware
app.use(express.cookieParser());
app.use(express.session({store: sessionStore, secret: "mysecret"}));
// any endpoint sets a cookie
app.get("/", function(req,res) {
res.send('ok');
});
// This endpoint reveals it
app.get("/session", function(req, res){
sessionStore.get(req.sessionID, function(err, data) {
res.send({err: err, data:data});
});
});
app.listen(3000);
Hitting / followed by /session results in a response of:
{
"err": null,
"data": {
"cookie": {
"originalMaxAge": null,
"expires": null,
"httpOnly": true,
"path": "/"
}
}
}
I suspect your issue may be how you are getting the sessionID from the socket, but it is definitely possible to extract a session from a MemoryStore. Also, remember that restarting the Express server will destroy all of your sessions so you'll need a new cookie after each restart.
You have to use a database to store your express session, then parse the cookie data inside the socket.io definition and with the information obtained get the session info from the database, here is a complete example:
https://stackoverflow.com/a/13098742/218418
You can also use the session ID parsed from the cookie and join the user into a "chat room" with the name of the session.

Set individual maxAge for sessions when using cookieSession() in connect/express

I am trying to use connect/express cookieSession() in order to store my node.js sessions in cookies (and thus, avoiding a server-side session store). This would help me to 'remember' the user when they log in and keep sessions alive even after server restarts.
I would like to do this with cookieSession():
app.use( express.cookieSession( { secret: 'secret_key' } ) );
app.use( function (req, res, next) {
if ( req.method == 'POST' && req.url == '/login' ) {
if ( req.body.remember ) {
req.session.cookie.maxAge = 30*24*60*60*1000; // Rememeber 'me' for 30 days
} else {
req.session.cookie.expires = false;
}
}
next();
});
However, this does not work, because req.session.cookie is undefined. I also tried the following, but it didn't seem to work:
app.use( express.session( { secret: 'secret_key' } ) );
app.use( function (req, res, next) {
if ( req.method == 'POST' && req.url == '/login' ) {
if ( req.body.remember ) {
req.cookies['connect.sess'].maxAge = 30*24*60*60*1000; // Rememeber 'me' for 30 days
} else {
rreq.cookies['connect.sess'].expires = false;
}
}
next();
});
Starting out with
app.use(express.cookieSession({ secret: config.server.cookieSecret }));
And changing it to
app.use(function(req, res, next) {
express.cookieSession({
secret: config.server.cookieSecret,
cookie: {
maxAge: req.param('remember') ? 20000 : 3000
},
})(req, res, next);
})
So, we create our own middleware, wrapped around the cookieSession middleware, changing the maxAge based on a param.
So, whenever you change the session you'll need to pass a remember in the body, query, or params( that's where req.param() looks ). In most cases, you only set a user_id to the session once, at login.
It's 3 seconds or 20 seconds to test and ensure it works.
And again, it might be not very helpful if you're setting stuff to your session a lot, but if you just set a user_id to session at login, this is all you need.
If you are setting lots of stuff to your session, you should know that data get passed around at every request, and you should save only the minimum to the session, like user_id, then look up the data you need for each request, to keep the overhead down on the user.
I think this does what you want:
// Using express.session instead of express.cookieSession
app.use(express.session({ secret : 'secret_key' }));
app.use( function (req, res, next) {
if ( req.method === 'POST' && req.url === '/login' ) {
if ( req.body.remember )
{
req.session.cookie.maxAge = 30*24*60*60*1000;
// needed to make the session `dirty` so the session middleware re-sets the cookie
req.session.random = Math.random();
}
else
{
req.session.cookie.expires = false;
}
}
next();
});
cookieSession does some funky stuff, like del req.session.cookie (not sure why).
You have to first set req.session.cookie so that you can set maxAge. Trying to use it before you set it gives req.session.cookie is undefined
express.cookieSession has default values which it accepts, see here. You should mention all the parameters you are going to use. You can set cookie via the following :
app.use(express.cookieSession({ secret: 'secret_key', cookie :{ path: '/', httpOnly: true, maxAge: 30*24*60*60*1000} });
A little late to the table but I thought this answer may help people going forward...
I was using cookie-session which doesn't create a cookie object on request.session. To properly implement rememberMe functionality using request.session.cookie I switched cookie-session to express-session and that solved everything. So now there is a cookie object on session and doing this inside of a request is possible...
npm install express-session
app.post('/login', function(request, response, next) {
passport.authenticate('local', function(err, user, info) {
if(err) return next(err);
if(!user) {
request.flash('loginMessage', info.message);
return response.redirect('/account/login');
}
request.login(user, function(err) {
if(err) return next(err);
if(request.body.rememberMe)
request.session.cookie.maxAge = 2592000000;
else
request.session.cookie.expires = false;
return response.redirect(options.redirect);
});
})(request, response, next);
});
This is also pretty late but it might help other people.
It seems like to me the best way to persist your session data is to store it in something like redis. The question asked for a way that didn't use server storage, but I think he was referring more to MemoryStore. Maybe not but either way this is what I did.
I used express-session and connect-redis
npm install -g connect-redis
npm install -g express-session
Then you configure stuff.
// session modules
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session')
var redisStore = require('connect-redis')(session); // this sets up Redis to work with your session cookies
var app = express();
Then you just initiate your session with the store option set to your redisStore.
The maxAge part sets the lifetime of each session to an hour, the session middleware resets it when it's accessed.
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({
store: new RedisStore({
host:'127.0.0.1',
port:6380,
prefix:'sess'
}),
cookie: {maxAge: 3600000 },
secret: 'session_secret'
}));
Now when a client connects, express should store the session data automatically in a Redis data structure. Since it's not just cached in memory, your server can crash and still have all the relevant session data still available at the IP address and and port specified.
Yummy seems to allow modifying cookies expiry after creation.

Resources