UnhandledPromiseRejectionWarning: Error: The client is closed on NodeJS - node.js

I am trying to add Redis to my website for session management but I get the below error:
UnhandledPromiseRejectionWarning: Error: The client is closed
Below is my code:
I have kept only the relevant redis lines to avoid verbosity.
const express = require('express');
const app = express();
const session = require('express-session');
const redis = require('redis');
const connectRedis = require('connect-redis');
const RedisStore = connectRedis(session)
const redisClient = redis.createClient({
host: 'localhost',
port: 6379
})
redisClient.on('error', function (err) {
console.log('Could not establish a connection with redis. ' + err);
});
redisClient.on('connect', function (err) {
console.log('Connected to redis successfully');
});
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: 'secret$%^134',
resave: false,
saveUninitialized: false,
cookie: {
secure: false, // if true only transmit cookie over https
httpOnly: false, // if true prevent client side JS from reading the cookie
maxAge: 1000 * 60 * 10 // session max age in miliseconds
}
}))
app.use(
session({
name: 'AuthCookie',
secret: 'some secret string!',
resave: false,
saveUninitialized: true
})
);
app.listen(port, () => {
console.log("We've now got a server!");
console.log('Your routes will be running on http://localhost:3000');
});
I read that I should add await client.connect() but I am not sure

Related

My req.session from Express is undefined, nothing works

I searched a lot to fix my problem but nothing works, the req.session is undefined, what am I doing wrong ?
In server.js :
const app = express();
const session = require('express-session');
const redis = require('redis');
const redisClient = redis.createClient();
async function connectRedis() {
try {
const redisStore = require('connect-redis')(session);
await redisClient.connect();
app.use(
session({
name: '_redisPractice',
secret: 'myStackOverflowkey',
saveUninitialized: true,
cookie: { maxAge: 1000 * 60 * 60 * 24, secure: false, httpOnly: true },
resave: false,
store: new redisStore({ host: 'localhost', port: 6379, client: redisClient, ttl: 86400 }),
}),
);
} catch (err) {
console.log(err);
}
}
connectRedis();
app.post('/api/auth/signin', (req, res) => {
console.log('Well.....', req.session);
});
The redis-CLI's monitor doesn't show anything, same for my server.
Thank you in advance

My cookie is not set in Browser of studio.apollographql explorer

i am trying to set cookie on apollo Studio explorer, my redis setup successfully store the cookie, but nothing is set on the browser.
Please What am i doing wrong ?
when make a monitoring of redis with redis-cli ,i can see that the token is receive.
i am using : apollo-server-express "^3.3.0", and express-session "^1.17.2"
async function startServer() {
const app = express();
const httpServer = http.createServer(app);
const RedisStore = connectRedis(session);
const redisClient = redis.createClient({
host: "127.0.0.1",
port: 6379,
});
app.use(
session({
name: "pid",
store: new RedisStore({
client: redisClient,
}),
cookie: {
maxAge: 1000 * 60 * 10,
httpOnly: false,
secure: true,
sameSite: "none",
},
saveUninitialized: false,
secret: "EOJ7OmvIAhb2yJpCI947juj6F8CppHCp",
resave: false,
})
);
const server = new ApolloServer({
schema,
context: createContext,
formatError: (error) => {
return {
message: error.message,
};
},
});
await server.start();
server.applyMiddleware({
app,
cors: { credentials: true, origin: "https://studio.apollographql.com" },
});
await new Promise((resolve: any) =>
httpServer.listen({ port: process.env.PORT }, resolve)
);
}
startServer().catch((err) => console.log(err));

Express-session not set cookies in the browser after deploying the server application on the Heroku platform

I faced the issue with express-session and I have tried to solve it.
Here is what I found some solutions.
https://github.com/expressjs/session/issues/633
But honestly to say it doesn't work for me.
When I run a server on my local machine everything works fine and the cookie set and contained in the browser.
But I have no idea why after deploying on the Heroku platform the cookie option not set and not contained in the browser.
Configuration
import {DB_HOST} from "./configs/database";
import {PORT} from "./configs";
import session from "express-session";
import mongoDBSession from 'connect-mongodb-session'
//Session db
const DBSessions = mongoDBSession(session)
//Create express app
const app = express();
app.use('/public', express.static('public'))
//Config Object to Avoid Deprecation Warnings
const dbOptions = {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true
};
//MongoDB
//Connection database
mongoose.connect(DB_HOST, dbOptions);
//Store Connection Object
const db = mongoose.connection;
//Connection events
db.once("open", () => {
console.log("Connected to MongoDB database...");
}).on("error", (err: string) => {
console.log(err);
});
//Store session
const sessionStore = new DBSessions({
uri: DB_HOST,
collection: 'sessions'
})
//https://github.com/expressjs/session/issues/633
app.set('trust proxy', 1);
app.use(routesArray,
session({
secret: SESSION,
resave: false,
saveUninitialized: false,
store: sessionStore,
cookie: {
sameSite: false,
maxAge: MAX_AGE,
secure: false,
httpOnly: true
}
})
)
//Starting server
app.listen(PORT, () => {
console.log(`Listening on port ${PORT}`);
});

In node, how do I detect how much time is left in a redis session?

In node using express.js, I have a redis-based session set up thusly:
// Redis session
const sessionStore = new RedisStore({
client: getRedisClient(),
prefix: 'bl:',
ttl: parseInt(config.sessionTTL, 10),
logErrors: (err) => {
log.error('Redis session error', {
err_message: err.message,
err_stack: err.stack
});
}
});
app.use(session({
secret: config.sessionSecret,
store: sessionStore,
resave: false,
saveUninitialized: false
}));
The ttl parameter is typically set to 30 minutes, at the end of which the session dies quite nicely.
I now need to advise the user when 5 minutes or less remains of their session but can't find a way of determining when I hit that landmark.
I assumed (rather naively) the amount of time left would be stored in req.session, but when I display that it typically only shows the following:
Session {
cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true },
cookieChoiceConfirmationBannerSeen: 'seen',
accessPage: '/decision/application-reference',
appRef: '12345678'
}
How can I find how much time is left on my session? Should I use maxAge or expiry rather than ttl?
========= EDIT =========
Additial info:
the code for getRedisClient:
const redis = require('ioredis');
const config = require('../config/config');
let client;
const getRedisClient = () => {
if (!client) {
client = redis.createClient({
host: config.redisHost,
port: config.redisPort
});
}
return client;
};
module.exports = {
getRedisClient
};
You should be able to get the ttl of the entry itself by calling your redisClient with the corresponding key, i.e. your defined key-prefix (default sess) and the session-id. Something like this should work:
const prefix = 'bl:';
const redisClient = getRedisClient();
// Redis session
const sessionStore = new RedisStore({
client: redisClient,
prefix: 'bl:',
ttl: parseInt(config.sessionTTL, 10),
logErrors: (err) => {
log.error('Redis session error', {
err_message: err.message,
err_stack: err.stack
});
}
});
app.get('/get-session-ttl', (req, res) => {
redisClient.ttl(`${prefix}${req.session.id}`,((err, reply) => {
console.log("the remaining ttl is "+reply);
res.send("...");
}));
})

set up mssql-session-store in node.js

I'm trying to use mssql-session-store as nodejs (express) store for session:
https://www.npmjs.com/package/mssql-session-store
This is how it should be configured(from npm page):
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: false,
store: new MssqlStore(options) // see options below
}));
var options = {
connection: existingConnection,
ttl: 3600,
reapInterval: 3600,
reapCallback: function() { console.log('expired sessions were removed);
}
};
My problem is with the options.connection. It should be "Optional instance of a Connection from mssql".
This connection establishment is an async process (from the npm page):
const sql = require('mssql')
async () => {
try {
await sql.connect('mssql://username:password#localhost/database')
const result = await sql.query`select * from mytable where id =
${value}`
console.dir(result)
} catch (err) {
// ... error checks
}
}
This is how express session is being defined in the nodejs initialization:
app.use(session({
name:<session name>,
key: <session key id>,
resave:false,
saveUninitialized:false,
secure: process.env.NODE_ENV ==="production",
secret:<secret string>,
store: new MssqlStore(options), //This is optional - for use when using sql server as a store
cookie:{
//httpOnly: true,
secure: process.env.NODE_ENV ==="production",
expires: config.expressSession.cookieLifeTime
}
}));
The problem is that establishment of the connection is an async process. I've tried several versions to both use the express-session in the application, but doing so just after the connection has been set up (async).
See my basic code (initialization of node.js - servre.js file):
const express = require('express');
const app = express();
const sql = require('mssql');
const session = require ('express-session');
const MssqlStore = require ('mssql-session-store')(session);
var sqlStore = null;
var store = null;
var mssqlConfig =
{
user: <user>
password: <password>,
server: <server name>
database: <database>,
options: {
encrypt: true // Use this if you're on Windows Azure
}
}
I've tried setting the session in the app in the connetion promise:
var sqlConnection = null;
async function getConnectedConnectionOptions()
{
try
{
sqlConnection = await sql.connect(<connection string>);
return await Promise.resolve(sqlconnection: sqlConnection);
} catch (err)
{
sqlConnection = null;
}
}
getConnectedConnectionOptions(),then(result =>
app.use(session({
name:<session name>,
key: <session key id>,
resave:false,
saveUninitialized:false,
secure: process.env.NODE_ENV ==="production",
secret:<secret string>,
store: new MssqlStore(result) ,
cookie:{
//httpOnly: true,
secure: process.env.NODE_ENV ==="production",
expires: config.expressSession.cookieLifeTime
}
}));
but then there's a scope problem where session is not defined in the global app.
Please support.
this is inside example folder in the mssql-session-store module
var dbConfig = {
server: "localhost\\sqlexpress",
database: "sessiontest",
user: "sa",
password: "atonan"
};
var start = function(callback) {
callback = callback || function() {};
sql.connect(dbConfig, function(err) {
if (err) return callback(err);
var app = express();
app.use(session({
secret: '991E6B44882C4593A46C0DDFCA23E06A',
resave: false,
saveUninitialized: false,
store: new MssqlStore({ reapInterval: 10, ttl: 10 })
}));

Resources