I have 2 routes on the backend of my app.
The first one sets a session using redis and using a different route i try to retrieve the session that was saved prior. However, when trying to retrieve the session, i get a different one from the one i created.
this is how i create a session and assign a property to it:
app.post("/login", (req, res) => {
req.session.userId = 1
});
and this is how i try to retrieve it:
app.get("/cookie", (req, res) => {
res.json(req.session);
});
But when the req.session of the get request is logged, I get one without the property userID.
Even though, i am able to view the key and value of the session using the redis-client with the keys and mget command.
this is how the cookie and session is configured
app.use(
session({
name: "cookie",
store: new RedisStore({ client: redisClient }),
secret: "xxxxx",
resave: false,
saveUninitialized: false,
cookie: {
secure: false,
httpOnly: false,
maxAge: 1000 * 60 * 10,
},
})
);
and this is the redisClient:
const redisClient = redis.createClient({
host: "localhost",
port: 6379,
});
How do I properly retrieve the session that i set on the post request? Am I using redis entirely wrong or am i just missing something?
Thanks!
Related
I have a problem saving data to the Express Session middleware. I am using a Vue.js frontend to communicate with the server which is running at localhost:8080. The server runs on localhost:3002.
I suspect that the interaction between the Vue app and the server may be the source of the problem as I have tried tests with a bare bones Express app that serves HTML as simple template literals and req.session.save() works fine.
Here is my code.
vue.config.js
module.exports = {
"transpileDependencies": [
"vuetify"
],
devServer: {
"https": true
}
}
index.js(Express server)
const corsOptions = {
origin: 'https://localhost:8080', // Have tried with and without these options
credentials: true,
};
app.use(cors(corsOptions));
// Set up app to use session
let sess = {
secret: 'What secret?',
resave: false, // Tried true
saveUninitialized: false, // Tried true
cookie: {secure: process.env.NODE_ENV=="prod",httpOnly: false}, // Tried true
store: MongoStore.create({ mongoUrl: process.env.DB_URL,
ttl: 14 * 24 * 60 * 60 }) // = 14 days. Default
}
app.use(session(sess));
Login route where data is being set to the session.
app.post('/api/login', async (req, res) => {
...
request(options, function (error, response) {
if (error) throw new Error(error)
let fm_res = JSON.parse(response.body)
req.session.FM_TOKEN = fm_res.response.token
req.session.save()
console.log('TOKEN STORED IN SESSION :: ', req.session) // token present in session here
res.json({message: 'Token saved in session...', status: 200})
});
});
Separate route where token is not accessible.
// CHECK AUTH
app.post('/api/token_auth', async (req, res) => {
let authToken = req.session.FM_TOKEN
console.log('TOKEN FROM SESSION : ', authToken) // undefined
....
});
I have researched and tried various solutions suggested here on SO but nothing I have found from any answers has worked. Can anyone point me in the right direction to solve this one as I am out of ideas. Thanks in advance.
UPDATE
I have tested the above endpoints with with Postman and they work, i.e. the /api/token_auth has access to the token saved on the session. So, it appears the problem might be connected to the fact that my frontend is not using https but http to make these calls.
I have tried using httpOnly: false setting in the session.cookie as suggested in this SO answer, but it still doesn't work. I am out of ideas.
Does anyone know how https requirement can be circumvented for development purposes?
Let say that I have "home" route and "food" route. In "home" route I collected user data from database, I want to pass username to "food" route. I want to use session to do that, but I didn`t find solution for that. In PHP is very easy by using
$_SESSION['username'] = username;
From google I learned that in node.js I can do something like this
const express = require('express');
const session = require('express-session');
const app = express();
var sess;
app.get('/',function(req,res){
sess=req.session;
sess.email; // equivalent to $_SESSION['email'] in PHP.
sess.username; // equivalent to $_SESSION['username'] in PHP.
});
But I learned as well that using a global variable for the session won’t work for multiple users. You will receive the same session information for all of the users.
This person recommend to use Redis, but it require to install another software. Is there any better way to save data to session variables in node.js and pass it to another route similar to what I can do in PHP?
You have to create a session object and pass it to expressjs app in order to access the sessions.
This is the example from the documentation:
var app = express()
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}))
And then you can access the session from the request object in handlers:
app.get('/', function(req, res, next) {
if (req.session.views) {
req.session.views++
res.setHeader('Content-Type', 'text/html')
res.write('<p>views: ' + req.session.views + '</p>')
res.write('<p>expires in: ' + (req.session.cookie.maxAge / 1000) + 's</p>')
res.end()
} else {
req.session.views = 1
res.end('welcome to the session demo. refresh!')
}
})
how to generate cookie using node js , I am using express-session node plugin to generate the cookie .please tell me where I am doing wrong
install express-session plugin
app.js
const session = require('express-session');
app.use(session({
secret: 'asdassadsazz',
resave: true,
saveUninitialized: true,
//cookie: { secure: true }
}));
app.use(passport.initialize());
app.use(passport.session());
passport.js
passport.serializeUser(function(id, done) {
console.log('ddd');
// console.log(user);
done(null, id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
controller.js
register: async (req, res, next) => {
console.log(req.body);
try {
const result = await db.User.create({
email: req.body.email,
password: req.body.password
})
console.log(result.id);
req.login(result.id,function () {
res.json({message:"Registration successfully"});
})
} catch (e) {
console.log(e)
}
},
It should generate cookie and store in browser,but it is not generating any cookie.
server log
Executing (default): SHOW INDEX FROM `Users` FROM `sql12252060`
app is running on 5000
OPTIONS /users/register 204 1.943 ms - 0
{ email: 'a#g.com', password: '1' }
email element
Executing (default): INSERT INTO `Users` (`id`,`email`,`password`) VALUES (DEFAULT,'a#g.com','$2a$10$zhTaqEbEeMOaD8F..CQYRufALc5dD4l899qMKRw0QRxIWvrPMSlpq');
17
ddd
POST /users/register 200 932.036 ms - 39
is the issue of different domain .my server is running on 5000 port and client is running on 3000
Please note that secure: true is a recommended option. However, it requires an https-enabled website, i.e., HTTPS is necessary for secure cookies. If secure is set, and you access your site over HTTP, the cookie will not be set. If you have your node.js behind a proxy and are using secure: true, you need to set "trust proxy" in express:
var app = express()
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}))
resave option should be false.
resave:
Forces the session to be saved back to the session store, even if the session was never modified during the request. Depending on your store this may be necessary, but it can also create race conditions where a client makes two parallel requests to your server and changes made to the session in one request may get overwritten when the other request ends, even if it made no changes (this behavior also depends on what store you're using).
The default value is true, but using the default has been deprecated, as the default will change in the future. Please research into this setting and choose what is appropriate to your use-case. Typically, you'll want false.
How do I know if this is necessary for my store? The best way to know is to check with your store if it implements the touch method. If it does, then you can safely set resave: false. If it does not implement the touch method and your store sets an expiration date on stored sessions, then you likely need resave: true.
I'm trying to get sessions variables working in my Express Node.js project, using the express-session module. I'm not getting any errors, and setting session variables seems to work, however they don't persist across requests. Here's a simplified bit of my code:
server.js
var express = require('express');
var bodyParser = require('body-parser');
var session = require('express-session');
var app = express();
app.use(bodyParser.json());
// Sessions
app.use(session({
secret: config.secret
}));
app.use('/api/projects', require('./controllers/api/projects'));
var server = app.listen(3000, function() {
console.log('Server listening on', 3000)
});
api/projects.js router
var router = require('express').Router()
router.get('/set', function(req, res, next) {
req.session.test = "test";
res.status(200).json({"test":req.session.test});
});
router.get('/current', function(req, res, next) {
res.status(200).json({"test":req.session.test});
})
Setting the variable seems to works...
The /set API call should set a session variable called test. This API call appears to work when I try it with curl:
curl -X GET localhost:3000/api/projects/set --cookie "connect.sid=s%3AyP3a8siRuA-5jDxWH4T03UxNpFd6lfBq.Ha8b8eJxbtW8fAJlbgR9jumfmBpJIXNE6444fOb2Jro"
{"test":"test"}
This is also confirmed in the console log:
Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true },
test: 'test' }
...however next time I check it it's not set
When I try to check the variable with my second API call, it appears to be undeclared:
curl -X GET localhost:3000/api/projects/current --cookie "connect.sid=s%3AyP3a8siRuA-5jDxWH4T03UxNpFd6lfBq.Ha8b8eJxbtW8fAJlbgR9jumfmBpJIXNE6444fOb2Jro"
{}
This is confirmed in the console log, the test variable is no longer set:
Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true } }
How can I ensure my sessions variables persist across requests?
(PS: I've been stuck on this for a while and any small comment on hints or resolution is very welcome, even if you're not sure you've got the answer)
I can see two possible reasons for this.
First, you could've messed up with cookies in curl.
You could ensure that you've set your cookies correctly by checking http response. If it contains Set-Cookie header with a new connect.sid then you did something wrong.
Alternatively, you could use a web browser with native cookies support to guard yourself against such mistakes.
Second, you may've restarted your sever between two requests.
Since you didn't specify any persistent store for your sessions, no data will persist between node.js server restarts.
If you want session data to persist after node.js server stops or restarts, you should consider using some persistent session store (i.e. redis-store).
I am still quite new to node and am experimenting with session management using express + redis.
My current project requires the user to be redirected to an external site to authenticate. After authentication, the browser is redirected to a callback url that i've specified. I require session data to persist across the redirect.
My implementation is as follows:
User triggers POST call to nodeJS server, where I persist data to session by req.session.foo = 'bar' and then return an auth_url to the browser.
Browser redirects using window.location.replace(auth_url); to external site for authentication
After authentication, browser is redirected to localhost:3000/mycallbackurl which is a route defined below (pardon the poor formatting):
router.get('/mycallback', function(req, res) {
console.log("data at callback: " + req.session.foo);
//do other stuff
});
My problem now is that the console prints: data at callback: undefined at the callback route.
Is this a problem with my redis setup, or am I just missing something here?
So far i've ascertained that redis is working by incrementing a value stored in req.session on each browser refresh and printing it.
My redis setup is as follows:
var session = require('express-session');
var RedisStore = require('connect-redis')(session);
app.use(cookieParser());
app.use(session({ store: new RedisStore({
host: 'localhost',
port: 6379,
db: 1,
cookie: { maxAge: (24*3600*1000*30)},
}), secret: 'keyboard cat',
saveUninitialized: true,
resave: true
}));
Thanks for reading and look forward to your replies!
After a redirect (res.redirect), the res and req objects are recreated. That means if you added any parameters to these objects, you need to be sure they are re-added to the req or res objects on each request.