I am trying to include sessions only for some routes (the authentication ones) but I am having a problem because of the error page routes:
I have this:
app.use(session({
secret: config.secrets.session,
saveUninitialized: false,
resave: false,
store: sessionStore,
proxy: true,
cookie: {
maxAge: config.token_duration,
secure: false
}
// rolling: false
}));
app.use('/api/user', require('./api/user'));
app.use('/api/auth', require('./api/auth'));
app.route(['/error/500','/error/404','/user/settings'])
.get((req, res) => {
res.sendFile(path.resolve(app.get('appPath') + '/index.html'));
});
app.route('/*/*')
.get(errors[404]);
app.use(errors[500]);
So, If I use it like this, all the pages in my application will create a session (which I don't want). If I move the session section after the error routes, I will never get to the api routes because it will reach the 404 route.
Thanks in advance
Middleware can be associated with only certain routes and the order in which it is specified matters. There are a number of ways to do that and how to best implement it depends upon the paths your site uses and how you can most easily create a link between path and whether it should or should not have the session middleware on it.
One simple thing to do would be to put your error route handlers BEFORE your session middleware. Then, those route handlers would "handle" the request first and the session middleware would never get called.
app.route(['/error/500','/error/404','/user/settings'])
.get((req, res) => {
res.sendFile(path.resolve(app.get('appPath') + '/index.html'));
});
app.use(session({
secret: config.secrets.session,
saveUninitialized: false,
resave: false,
store: sessionStore,
proxy: true,
cookie: {
maxAge: config.token_duration,
secure: false
}
// rolling: false
}));
Other things you can do:
Put a path on your session middleware so it is only invoked for certain paths in your site (all authenticated pages should be below that path).
Create your own middleware handler that checks to see if the path is /error and if not, then it invokes the session middleware handler. If it is /error, then don't invoke the session middleware.
This last one could be done like this:
const sessionHandler = session({
secret: config.secrets.session,
saveUninitialized: false,
resave: false,
store: sessionStore,
proxy: true,
cookie: {
maxAge: config.token_duration,
secure: false
}
// rolling: false
});
app.use(function(req, res, next) {
// if path does not start with /error/, then invoke session middleware
if (req.url.indexOf("/error/") !== 0) {
return sessionHandler(req, res, next);
} else {
next();
}
});
You can also chain/compose multiple middleware using Express.router() as mentioned in this example: Express: composing middleware
And then apply that composed router (of chained middleware) as a specific route handler.
Related
I'm using express-session to store session cookie. I can see Set-Cookie connect.ssid under the response header but for some reason it is not getting stored in the cookie.
I'm wondering if this is a CORS issue, my app file looks like this. Should I change something here to make it work.
const session = require('express-session');
const config = require('config');
var MemoryStore = require('memorystore')(session);
module.exports = function (app) {
// app.use(
// session({
// secret: 'key sign',
// resave: false,
// saveUninitialized: false
// })
// );
app.use(express.json());
app.use(cors({ credentials: true }));
enter code here
app.set('trust proxy', 1);
app.use(
session({
saveUninitialized: false,
cookie: { maxAge: 86400000 },
store: new MemoryStore({
checkPeriod: 86400000
}),
resave: false,
cookie: { secure: false },
secret: config.get('sessionStorage')
})
);
app.use('/api/users', users);
Here is how I fixed this.
Add SSL to both frontend and backend.
If it is self-signed, ensure browser trust it. For example, if you're using mac, go to keychain, select specific certificate and select always trust option.
Restart the system. Only then SSL will be properly set otherwise there would still be insecure badge in the navigations.
I was making a React project, and I was using Express for backend. I set http://mini-api.moonlab.ga as a virtual host for Express server.
I sent a HTTP Request to express server with Fetch:
fetch("http://mini-api.moonlab.ga/login/", {
credentials: "include"
})
and as I expected there was a CORS error. So I installed cors package, and I set code like this in Node.js:
app.use(cors({
origin: true,
credential: true
}));
And I respond to client from server like this:
app.get("/login", (req, res) => {
const session = req.session;
if (session.miniAccount == undefined) {
session.miniAccount = Math.floor(Math.random() * 1000000);
}
res.writeHead(200, {"Access-Control-Allow-Credentials": true});
res.write(String(session.miniAccount));
res.end();
})
After I did like this, there wasn't any CORS error, but the session don't persist. When I send a request again, the session data keeps changes.
Well how to make session persist?
Server's session code:
app.use(express_session({
secret: secret.app_key,
resave: false,
saveUninitialized: true
}));
You may try setting a maxAge value inside cookie
...
const session = require("express-session");
...
app.use(
session({
secret: secret.app_key,
resave: false,
saveUninitialized: true
cookie: {
maxAge: 3600000 //session expires in 1 hr
}
})
);
I solved it myself by editing package.json.
I added "proxy": "mini-api.moonlab.ga" in package.json.
Than I edited fetch().
previous
fetch("http://mini-api.moonlab.ga/login")
new
fetch("/login")
And it worked.
I would like to disable the session creation for a specific route, as "/app/....";
I tried one way by using the code see below :
pool = mysql.createPool(mysqlOptions);
var sessionConnection = mysql.createConnection(mysqlOptions);
var sessionStore = new MySQLStore(mysqlOptions, sessionConnection);
app.use(function(req, res, next){
if (!req.path.startsWith("/app/"))
session({
key: 'x',
secret: 'x',
store: sessionStore,
resave: false,
saveUninitialized: true,
cookie: {maxAge: moment().endOf('days').diff(moment())} })(req, res, next);
else
next();
});
I have the warning message see bellow and after few minutes, the server is not reachable.
MaxListenersExceededWarning: Possible EventEmitter memory leak
detected. 11 disconnect listeners added to [MySQLStore]. Use
emitter.setMaxListeners() to increase limit
Could somebody explain me ? Thanks in advance.
If you put the route declaration BEFORE your session middleware, then the session will not be created for that specific route handler.
app.use("/app", appRouter); // this will be handled before session is created
app.use(session(...));
If you want to call the session dynamically the way you are in your code, then you should create the session middleware once and then call that dynamically:
pool = mysql.createPool(mysqlOptions);
const sessionConnection = mysql.createConnection(mysqlOptions);
const sessionStore = new MySQLStore(mysqlOptions, sessionConnection);
const sessionMiddleware = session({
key: 'x',
secret: 'x',
store: sessionStore,
resave: false,
saveUninitialized: true,
cookie: {maxAge: moment().endOf('days').diff(moment())}
});
app.use(function(req, res, next){
if (!req.path.startsWith("/app/"))
sessionMiddleware(req, res, next);
else
next();
});
The node application uses passport-ldap for authentication, and the issue is that it works like a charm in the development environment, but the are problems in the production one. When the route is being changed, I lose the user's session because the connect.sid (the cookie) of the Application is being changed, because I have a new setCookie response.
I am using express 4.17.1 and express-session 1.16.2, so from my research I found that i do not have to use cookieParser. I also think that there is no issue with the serialize and deserialize of the user and passport functionality.
// Static folder set
app.use(express.static(path.join(__dirname, 'public')));
// Body parser middleware
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.set('trust proxy', 1) //trust first proxy
// Express session midleware
app.use(session({
secret: 'abc',
resave: true,
saveUninitialized: true,
cookie: { secure: true }
}));
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
...
// Use routes of the application
app.use('/users', users);
I found the solution and i post it for future reference, in case someone else faces a similar issue.
I used the cors module and set it like that
app.use(cors({credentials: true}));
also in production enviroment you have to use a store to hold the cookie. This was obvious but i missed it. So i used
const MongoStore = require('connect-mongo')(session);
app.use(session({
secret: 'abc',
resave: false,
saveUninitialized: false,
cookie: { secure: true,
maxAge: 6*60*60*1000 },
store: new MongoStore({ mongooseConnection: mongoose.connection })
}));
Session initialize in express.js also used passport.js for local-authentication which is working fine. But the session/cookie is not working
app.use(serveStatic(__dirname + '../../dist'));
mongoose.connect(config.database, function(err){
if(err) console.log(err);
console.log('Connected to DB');
})
app.use(cors({
origin:['http://localhost:8080'],
credentials: true // enable set cookie
}));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser.urlencoded({ 'extended': 'false' }));
// required for passport
require('./config/passport')(passport); // pass passport for configuration
app.use(session({
secret: config.secret,
resave: true,
saveUninitialized: true,
cookie: { secure: true }
}));
// session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
Get request with axios is below
axios.get(this.url + '/user', {withCredentials: true})
.then(response => {
console.log(response);
})
.catch(e => {
this.errors.push(e)
})
Refer tutorial to store sessions or cookies using passport.js and express.js
app.use(session({
secret: config.secret,
resave: true,
saveUninitialized: true,
cookie: { secure: true }
}));
instead of this try:
app.use(express.session({
secret: config.secret,
resave: true,
saveUninitialized: true,
cookie: { secure: true }
}));
app.use(passport.session());