I switched from memorystore to using Redis and I also use MongoDB locally.
Similar posts that I have read are not relevant or helpfull.
Basicly, if the router function try's to set a value to req.session the node app shuts down.
I am new to Redis, so maybe it is something obvious that I don't see?
// in app
var app = express();
var cookieParser = express.cookieParser('secret');
app.configure(function () {
app.use(express.bodyParser());
app.use(cookieParser);
app.use(express.session({secret: 'secret', store: othermodule.getSessionStore()}));
// othermodule
var RedisStore = require('connect-redis')(express);
var sessionStore = new RedisStore({
host: 'localhost',
port: 6379,
db: 2,
pass: 'RedisPASS'});
thanks
Try removing the password in your options you pass to RedisStore.
If you want you can require the clients to give a password when connecting. But by default no password is required for clients to connect. If no password is required and you give a password, the client will try authenticating using the given password which will cause a connection failure. The fallback to using no password is not allowed at the client. Because of which you were getting session as undefined.
See here and here for configuring passwords.
Related
I've been trying to use connect-redis to use express session store with AWS Elasticache.
The redis server at AWS I used is using Encryption in-transit, encryption at-rest and Redis AUTH token.
i am using Passport with local strategy to authenticate users
This is how it looks in app.js when I configure it:
const express = require('express'),
app = express(),
session = require('express-session'),
awsHandler = require('./awsHandler'),
passport = require('passport'),
....
....
awsHandler.retrieveServiceCredentials('session').then(keys => {
let secret = keys.session_key;
let redis_auth = keys.redis_auth;
const redis = require('redis');
const redisClient = redis.createClient({
host: 'master.redis-connect.abcd.efg.cache.amazonaws.com',
port: REDIS_PORT,
auth_pass: redis_auth,
tls: { checkServerIdentity: () => undefined }
});
const redisStore = require('connect-redis')(session);
app.use(session({
secret: secret,
resave: false,
saveUninitialized: false,
store: new redisStore({
client: redisClient
})
}));
});
....
....
app.use(passport.initialize());
app.use(passport.session());
The thing is I try to connect to my website, and I get no req.session or req.user (when before using SQLite with connect-sqlite3 package, I had req.user after logging in).
I noticed nothing gets stored in redis, when I connect to the Redis Server and type KEYS * there are no keys. However, when I try to set a key in the Redis server hardcoded in app.js with:
redisClient.set('key', 'value')
It IS setting the key and value in the server (when typing KEYS * we can see it there).
So I do successfully establish connection to the redis server with the client library, however, it seems something happens there that I don't configure properly so the sessions gets stored in the Redis.
I am on AWS environment (Elastic Beanstalk, Elasticache).
hank you for reading and helping!
Best regards.
I solved it, it was a problem in my code :
the awsHandler.retrieveServiceCredentials is an async function, and called after couple seconds.
In the flow, it was already initializing everything in the app (initializing passport session, defining routes, starting the node server to listen on port, etc...), and because the retrieveServiceCredentials returned later than that, the order was wrong, and it initialized everything in the app before we used app.use(prodSessionMiddleware), so therefore the session not included in the app.
We set an interval every second, and check a boolean if the 'then' was called, if it was called, we clear the interval and continue with our life :)
I'm looking for sessionstore for production app because I have error message:
Warning: connect.session() MemoryStore is not designed for a
production environment, as it will leak memory, and will not scale
past a single process
My code:
var express = require('express');
var ECT = require('ect');
var cookieParser = require('cookie-parser');
var compress = require('compression');
var session = require('express-session');
var bodyParser = require('body-parser');
var _ = require('lodash');
var passport = require('passport');
var expressValidator = require('express-validator');
var connectAssets = require('connect-assets');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(expressValidator());
app.use(methodOverride());
app.use(cookieParser());
app.use(session({
resave: true,
saveUninitialized: true,
secret: secrets.sessionSecret,
}));
app.use(passport.initialize());
app.use(passport.session());
var app = module.exports = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(app.get('port'), function() {
console.log('Express server listening on port %d in %s mode', app.get('port'), app.get('env'));
});
module.exports = app;
I don't know what is the best solution for my production app. I'm using sequelize as ORM with PostgreSQL.
I will be very grateful with any opinion.
Though an answer has been accepted, I think a more elaborated answer is in order, so that people who actually want to use Express with PostgreSQL for consistent session storage can have a proper reference.
Express has the session module to handle the sessions though it defaults to in-memory storage that is suitable for development stages but not for production
Warning The default server-side session storage, MemoryStore, is purposely not designed for a production environment. It will leak memory under most conditions, does not scale past a single process, and is meant for debugging and developing.
So for PostgreSQL there is a dedicated simple connector called connect pg simple
Once you import the connect-pg-simple you . need to pass it the session import like this:
const session = require('express-session')
const pgSession = require('connect-pg-simple')(session)
When you add the session as middleware you'll have to pass it its settings
app.use(session(sessionConfig))
and in your sessionConfig, this would be where you set all your session parameters you need to add a store option that would look like this (adding the full set of options though for the matter at hand just note the store option):
const sessionConfig = {
store: new pgSession({
pool: sessionDBaccess,
tableName: 'session'
}),
name: 'SID',
secret: randomString.generate({
length: 14,
charset: 'alphanumeric'
}),
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 7,
aameSite: true,
secure: false // ENABLE ONLY ON HTTPS
}}
The new instance of pgSesision takes two options, the pool which is the config setup to access the PostgreSQL DB and the table name.
The DB connection setting should look like this:
const sessionDBaccess = new sessionPool({
user: DB_USER,
password: DB_PASS,
host: DB_HOST,
port: DB_PORT,
database: DB_NAME})
Also note that the session pool must be initiated:
const sessionPool = require('pg').Pool
I got it working with connect-pg-simple.
Create a session table with the provided table.sql, and pass in a connection string or an object.
If you have just to store session you can use redis or maybe mongoDB if you want persistence.
Node.js express sessions work perfectly for me with this code:
var express = require("express");
var app = express();
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({
cookie: {maxAge: pembapp.dayInMilliseconds * 180},
secret: 'mysecret',
key: 'mykey'
}));
I can access req.session.whatever with no problem.
Now I want to use redis to store session data in case a server restart is needed, so the code becomes this:
var express = require("express");
var app = express();
var RedisStore = require('connect-redis')(express);
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({
cookie: {maxAge: pembapp.dayInMilliseconds * 180},
secret: 'mysecret',
key: 'mykey',
store: new RedisStore({
host: 'localhost',
port: 6379,
db: 2,
prefix: 'myprefix',
pass: 'mypasswd'
})
}));
When I add the redis code, req.session is now undefined! Can't figure this out for the life of me. Why would req.sesion "disappear" when I add a redis store for sessions???
I think we can close this one out. Perhaps I wasn't connecting to redis when req.session was undefined. I did find that I needed to explicitly call req.session.save() when using redis, which wasn't needed without redis.
Judging from the questions I've seen out there, ff someone could create a clear node.js example using redis-connect for persistent sessions, for node newbies, starting from scratch, I think you'd make a bunch of folks very happy.
Are you sure it is connecting to the Redis database?
I am trying to use passport-twitter and passport-facebook for authentication in an app that is using Redis for Express sessions. If I remove the connect-redis for storing sessions in express, everything works fine, but with the Redis sessions, I get the following error:
Error: OAuth authentication requires session support
| at Strategy.OAuthStrategy.authenticate
My code is below:
app.configure(function(){
app.set('port', process.env.PORT || port);
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser("supersecret"));
app.use('/html', express.static('html'));
app.use('/assets', express.static('assets'));
});
if (process.env.REDISCLOUD_URL) {
var rtg = require("url").parse(process.env.REDISCLOUD_URL),
redis = require('redis'),
connectRedisStore = require('connect-redis')(express),
authToken = rtg.auth.split(":")[1];
app.configure(function(){
app.use(
express.session(
{
secret: 'supersecret',
cookie: { maxAge: 60000 },
store: new connectRedisStore({
host: rtg.hostname,
port: rtg.port,
db: authToken[0],
pass: authToken[1]
})
}
)
);
app.use(passport.initialize());
app.use(passport.session(
{
secret: 'supersecret',
store: new connectRedisStore({
host: rtg.hostname,
port: rtg.port,
db: authToken[0],
pass: authToken[1]
})
}
));
});
}
Is it possible to use these together?
Edit:
On further debugging, it seems that using connect-redis for the express session store is not setting the req.session to anything. This is what is causing the problem. Unfortunately, I can't seem to make it work at all. Other people with the same issue have fixed it by putting the cookieParser line above the session line, but that's where it's always been in mine, so the issue is something else. I am at a loss.
Ok, after two days of searching and poking through the source code of all the node_modules involved (express, connect, connect-redis), I tracked down my problem to a simple stupid typo.
authToken = rtg.auth.split(":")[1];
The authToken here just provides the password (which is all that redis uses to connect). But to manually choose a database, you need to remove the [1] and pass in the first element as the db name, and the second as the pass. Hope it helps someone else out there!
I am trying to integrate Redis sessions into my authentication system written in Node.js.
I have been able to successfully set up Redis server, connect-redis and Express server.
Here is my setup (just the important bit):
var express = require("express");
var RedisStore = require("connect-redis")(express);
var redis = require("redis").createClient();
app.use(express.cookieParser());
app.use(express.session({
secret: "thisismysecretkey",
store: new RedisStore({ host: 'localhost', port: 6379, client: redis })
}));
Now... How do I actually create, read and destroy the session? I am aware that that is probably extremely simple. I have read tons of articles on how to setup connect-redis and many questions here on SO, but I swear each one stops on just the configuration and does not explain how to actually use it...
That should be all there is to it. You access the session in your route handlers via req.session. The sessions are created, saved, and destroyed automatically.
If you need to manually create a new session for a user, call req.session.regenerate().
If you need to save it manually, you can call req.session.save().
If you need to destroy it manually, you can call req.session.destroy().
See the Connect documentation for the full list of methods and properties.
Consider this code.
var express = require('express');
var redis = require("redis");
var session = require('express-session');
var redisStore = require('connect-redis')(session);
var bodyParser = require('body-parser');
var client = redis.createClient();
var app = express();
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
app.use(session({
secret: 'ssshhhhh',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
resave: false
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.get('/',function(req,res){
// create new session object.
if(req.session.key) {
// if email key is sent redirect.
res.redirect('/admin');
} else {
// else go to home page.
res.render('index.html');
}
});
app.post('/login',function(req,res){
// when user login set the key to redis.
req.session.key=req.body.email;
res.end('done');
});
app.get('/logout',function(req,res){
req.session.destroy(function(err){
if(err){
console.log(err);
} else {
res.redirect('/');
}
});
});
app.listen(3000,function(){
console.log("App Started on PORT 3000");
});
So you need to install connect-redis and pass your express-session instance to it.
Then in middleware initialize redisStore with server details like this.
app.use(session({
secret: 'ssshhhhh',
// create new redis store.
store: new redisStore({ host: 'localhost', port: 6379, client: client,ttl : 260}),
saveUninitialized: false,
resave: false
}));
I put ttl to 260, you can increase. After TTL reaches its limits, it will automatically delete the redis key.
In routers you can use req.session variable to SET, EDIT or DESTROY the session.
One more thing...
If you want custom cookie i.e not as same as in your Redis store you can use cookie-parser to set cookie secrets.
Hope it helps.
link : https://codeforgeek.com/2015/07/using-redis-to-handle-session-in-node-js/
You can also use the Redis monitor tool to see all the action in real time! When you refresh your app you will see the data appear in the console window.
redis-cli monitor
Sample Output for Sessions using tj/connect-redis
1538704759.924701 [0 unix:/tmp/redis.sock] "expire" "sess:F9x-YgbgXu1g7RG8tFlkwY3RV0JzHgCh" "3600"
1538704759.131285 [0 unix:/tmp/redis.sock] "get" "sess:F9x-YgbgXu1g7RG8tFlkwY3RV0JzHgCh"
1538704787.179318 [0 unix:/tmp/redis.sock] "set" "sess:Hl3LPbOBdKO44SG4zQHFn2gfdiWTwzWW" "{\"cookie\":{\"originalMaxAge\":3600000,\"expires\":\"2018-10-05T02:59:47.178Z\",\"secure\":true,\"httpOnly\":true,\"domain\":\".indospace.io\",\"path\":\"/\"},\"path\":\"/\",\"userAgent\":{\"family\":\"NewRelicPingerBot\",\"major\":\"1\",\"minor\":\"0\",\"patch\":\"0\",\"device\":{\"family\":\"Other\",\"major\":\"0\",\"minor\":\"0\",\"patch\":\"0\"},\"os\":{\"family\":\"Other\",\"major\":\"0\",\"minor\":\"0\",\"patch\":\"0\"}},\"ip\":\"184.73.237.85\",\"page_not_found_count\":0,\"city\":\"Ashburn\",\"state\":\"VA\",\"city_state\":\"Ashburn, VA\",\"zip\":\"20149\",\"latitude\":39.0481,\"longitude\":-77.4728,\"country\":\"US\"}" "EX" "3599"
1538704787.179318 [0 unix:/tmp/redis.sock] "set" "sess:Hl3LPbOBdKO44SG4zQHFn2gfdiWTwzWW" "{\"cookie\":{\"originalMaxAge\":3600000,\"expires\":\"2018-10-05T02:59:47.178Z\",\"secure\":true,\"httpOnly\":true,\"domain\":\".indospace.io\",\"path\":\"/\"},\"path\":\"/\",\"userAgent\":{\"family\":\"NewRelicPingerBot\",\"major\":\"1\",\"minor\":\"0\",\"patch\":\"0\",\"device\":{\"family\":\"Other\",\"major\":\"0\",\"minor\":\"0\",\"patch\":\"0\"},\"os\":{\"family\":\"Other\",\"major\":\"0\",\"minor\":\"0\",\"patch\":\"0\"}},\"ip\":\"184.73.237.85\",\"page_not_found_count\":0,\"city\":\"Ashburn\",\"state\":\"VA\",\"city_state\":\"Ashburn, VA\",\"zip\":\"20149\",\"latitude\":39.0481,\"longitude\":-77.4728,\"country\":\"US\"}" "EX" "3599"