How can i log express-session on socket.io connection? - node.js

the problem is when i log req.session.user i get the user results not problem, but when i try to log socket.request.session i get an empty session without the user data, even if i use socket.request.session.user i get user is undefined. whats the problem with it? i really need some help its for my college project which is in the next week
i've followed the docs on socket.io page : https://socket.io/how-to/use-with-express-session
but it doesn't seem like its sharing my session to the socket, im trying to access user data on socket connection
This is my session/socket.io setup
const session = require("express-session");
const sessionMiddleware = session({
secret: "testing",
resave: false,
saveUninitialized: false
});
const wrap = middleware => (socket, next) => middleware(socket.request, {}, next);
module.exports = {sessionMiddleware, wrap};
io.use(wrap(sessionMiddleware));
io.on("connection", (socket) => {
console.log(socket.request.session)
// On new post
socket.on("newPost", (post) => {
console.log(post)
})
console.log(socket.id)
});
and this is my login setup
router.post("/login", async (req, res) => {
const data = {
username: req.body.username.toString(),
password: req.body.password.toString()
}
console.log(data)
if(data.username === "") {
res.json({
status: "error",
message: "Username is required"
})
return;
}
if(data.password === "") {
res.json({
status: "error",
message: "Password is required"
})
return;
}
let user = await new userClass();
if(await user.login(data.username, data.password)) {
req.session.user = await user.getUser();
console.log(req.session.user)
res.redirect("/");
return
} else {
res.redirect("/entry?error=username or password is incorrect");
return;
}
})

Related

Change variable in Express Session

I'm using the express-session package and I want to change the variable "_id" in the session.
Here my session init
app.use(session({
secret: "secretshhhhhh",
resave: true,
saveUninitialized: false,
}))
After the login page I try to store the id with these few lines:
req.session._id = user._id.toString()
req.session.save(function (err) {
req.session.save(function (err) {
console.log(req.session)
})
})
The console.log print the session with the id, but when I try to get the _id in an other page express send me back a null object. Here an exemple of printing session without the _id
return res.status(200).send(req.session);
I tried many methods but none of these worked for me.
EDIT:
Here my whole function to put it in session
module.exports.login_post = async function (req, res) {
User.findOne({ email: req.body.email }, function (err, user) {
if (user == null) {
return res.status(400).send({
message: "User not found"
})
}
else {
if (user.validPassword(req.body.password)) {
req.session._id = user._id.toString()
req.session.save(function (saveErr) {
req.session.reload(function (reloadSave) {
console.log(req.session, saveErr, reloadSave)
})
})
}
}
})
}
Here my whole function to get it from session
module.exports.session_get = function(req, res) {
return res.status(200).send(req.session);
}
module.exports.session_destroy = function(req, res) {
req.session.destroy();
return res.status(200).send({
message: "Session detroyed"
});
}

[ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client in Express

The Cookie that I am sending from http://localhost:5000/users/register , is not being set into the header of http://localhost:5000/users/register. I am able to access the cookie in the body but not in the headers.
My App.js code is
require("dotenv").config();
const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
const fileUpload = require("express-fileupload");
const cookieParser = require("cookie-parser");
const users = require("./routers/users");
const app = express();
app.use(express.json());
app.use(cookieParser());
app.use(cors());
app.use(
fileUpload({
useTempFiles: true,
})
);
// connecting to MongoDB
const mongoURL = process.env.MONGO_URL;
mongoose
.connect(mongoURL, {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
})
.then(() => console.log("DataBase has been connected !"))
.catch((err) => console.log("Cannot connect to database", err.message));
// routes
app.use("/users", users);
const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log(`I am listening at ${port}`);
});
My Router's Code
const express = require("express");
const bcrypt = require("bcrypt");
const { Users, userSchema } = require("../models/user");
const jwt = require("jsonwebtoken");
const router = express.Router();
// registering
router.post("/register", async (req, res) => {
try {
const { name, email, password } = req.body;
console.log(name, email, password);
//console.log(Users);
//console.log(userSchema);
let user = await Users.findOne({ email });
if (user) return res.status(404).json({ msg: "The email already exists" });
if (password.length < 6)
return res.status(404).json({ msg: "The password is less than 6" });
// Hashing password
const newPassword = await bcrypt.hash(password, 10);
// creating a user and saving in db
user = await new Users({ name, email, password: newPassword });
await user.save();
// creating JWT token for authenticating the user
const accessToken = createAccessToken({ id: user._id });
const refreshToken = createRefreshToken({ id: user._id });
// Cookie is being sent in the headers to the listed "path"
res.cookie("refreshToken", refreshToken, {
httpOnly: true,
path: "/users/refreshtoken",
});
res.json({ accessToken });
//return res.json({ password, newPassword, user, accessToken, refreshToken });
} catch (err) {
return res.status(500).json({ msg: err.message });
}
});
router.get("/refreshtoken", (req, res) => {
try {
const rfToken = req.cookies.refreshToken;
if (!rfToken)
return res.status(400).json({ msg: "Please login or sign up" });
// verifying the token that we sent when user registered
// the token shows ig it's the registered user or not
jwt.verify(rfToken, process.env.REFRESH_TOKEN, (error, decoded) => {
if (error)
return res.status(400).json({ msg: "Please login or sign up" });
console.log(decoded);
const accessToken = createAccessToken({ id: decoded.id });
res.json({ decoded, accessToken });
});
res.json({ msg: "DS", rfToken });
} catch (error) {
return res.status(500).json({ msg: error.message });
}
});
const createAccessToken = (userID) => {
return jwt.sign(userID, process.env.ACCESS_TOKEN, { expiresIn: "1d" });
};
const createRefreshToken = (userID) => {
return jwt.sign(userID, process.env.REFRESH_TOKEN, { expiresIn: "7d" });
};
module.exports = router;
The Cookie is not being set to the header of the "/users/refreshtoken", it is being sent in the body, I can see the cookie in the body of "/users/refreshtoken" but not in the header. I don't know why.
This error is usually caused by improper asynchronous sequencing which causes you to have one or more code paths that can attempt to send multiple responses to the same incoming request.
I see an example of this in your router.get("/refreshtoken", ...) route handler. One place this problem can occur is here where it's marked:
router.get("/refreshtoken", (req, res) => {
try {
const rfToken = req.cookies.refreshToken;
if (!rfToken)
return res.status(400).json({ msg: "Please login or sign up" });
// verifying the token that we sent when user registered
// the token shows ig it's the registered user or not
jwt.verify(rfToken, process.env.REFRESH_TOKEN, (error, decoded) => {
if (error)
return res.status(400).json({ msg: "Please login or sign up" });
console.log(decoded);
const accessToken = createAccessToken({ id: decoded.id });
=====>
res.json({ decoded, accessToken });
=====>
});
=====>
res.json({ msg: "DS", rfToken });
=====>
} catch (error) {
return res.status(500).json({ msg: error.message });
}
});
This code will launch the asynchronous and non-blocking jwt.verify() function and then will immediately execute:
res.json({ msg: "DS", rfToken });
Then, some time later it will execute either:
return res.status(400).json({ msg: "Please login or sign up" });
or
const accessToken = createAccessToken({ id: decoded.id });
both of which will try to send a second response. It appears to me that your code in this route has three possible outcomes:
No token is present
Token is present, but not valid
Token is present and valid
That means you should have three non-overlapping responses. But, you have four places you send a response and they overlap, causing duplicate responses. I don't know exactly why you have the res.json({ msg: "DS", rfToken }); line of code as it is always run anytime there is a token present (whether valid or invalid). You need to fix that. Probably you should just remove that line of code entirely or replace one of the other responses with this line of code inside the jwt.verify() callback.

Not able to logout using express-session in node.js

I am using express-session in my node.js application for authentication. The login route works fine but I am not able to logout. The session remains there in my mongodb database with a new expiration time when the logout link is clicked.
I have tried req.session.destroy() and req.session.cookie.expires = new Date().getTime() for the cookie to get expired when logout button is clicked but nothing worked.
express-session code in index.js
app.use(expressSession({
secret: 'secret',
cookie: { maxAge: 60 * 60 * 24 * 1000 }, //if maxAge is set to anything between 1000 and 9000 the logout button works
resave: false,
saveUninitialized: false,
store: new mongoStore({
mongooseConnection: mongoose.connection
})
}));
loginUser.js
const bcrypt = require('bcrypt')
const User = require('../database/models/User')
module.exports = (req, res) => {
const {
email,
password
} = req.body;
// try to find the user
User.findOne({
email
}, (error, user) => {
if (user) {
// compare passwords.
bcrypt.compare(password, user.password, (error, same) => {
if (same) {
req.session.userId = user._id
res.redirect('/')
} else {
res.redirect('/auth/login')
}
})
} else {
return res.redirect('/auth/login')
}
})
}
storeUser.js
const User = require('../database/models/User')
module.exports = (req, res) => {
User.create(req.body, (error, user) => {
if (error) {
const registrationErrors = Object.keys(error.errors).map(key => error.errors[key].message)
req.flash('registrationErrors', registrationErrors)
return res.redirect('/auth/register')
}
res.redirect('/')
})
}
auth.js
const User = require('../database/models/User')
module.exports = (req, res, next) => {
User.findById(req.session.userId, (error, user) => {
if (error || !user) {
return res.redirect('/')
}
next()
})
}
logout.js
module.exports = (req, res) => {
req.session.destroy(() => {
res.redirect('/auth/login');
});
I expect the session to get destroyed and the page to be redirected to the login page. Can anyone tell me what i am doing wrong?
try this
module.exports = (req, res) => {
if(req.session) {
req.session.cookie.maxAge = 0
delete req.session
}
res.redirect('/auth/login')
}

Save and get the session or cookie with Nodejs and Express not working

I'm pretty new using NodeJs and Express. I'm trying to save a session or a cookie with the user when you log in, and then get it in some other calls. What I'm doing:
server.js: Where I declare the library and create the session.
const session = require('client-sessions');
app.use(session({
cookieName: 'session',
secret: 'JLB_SECRET',
secure: false,
duration: 30 * 60 * 1000,
activeDuration: 5 * 60 * 1000,
}));
login.js: Where the user logs in, here the cookie or session is saved well.
router.post('/login', function(req, res, next) {
console.log('hacemos login', req.session);
var users = req.body;
if (!users.pass || !users.email) {
res.status(400);
return res.json({
status: 400,
error: 'Bad data'
});
}
User.findOne({
email: users.email,
pass: users.pass
}, function(err, userFound) {
if (err || userFound === null) {
res.status(404);
return res.json({
status: 404,
error: 'User not found'
});
} else {
const userToSend = userDto.serviceToDto(userFound);
req.session.user = userToSend; // here is saved properly
console.log('pasamos la session', req.session.user);
return res.json({
user: userToSend,
token: createToken(userFound)
});
}
});
});
Competences.js: I try to get the session in another call, but it's always empty.
router.get('/competence/user/:id', function(req, res, next) {
console.log('veamos la sesion', req.session); //HERE IS ALWAYS EMPTY
Competence.find({
"idUser": mongojs.ObjectId(req.params.id)
}, function(err, competences) {
if (err) {
return res.send(err);
}
const competenceToSend = competenceDto.serviceListToDto(competences);
res.statusCode = 200;
return res.json(competenceToSend);
});
});
Does anybody what I'm doing wrong or how to do it?? Here is where I got the guide to do it: https://stormpath.com/blog/everything-you-ever-wanted-to-know-about-node-dot-js-sessions
Regardssss and thank you!

why my koa-passport authenticate parameter user is always undefined?

I'm trying to use koa-passport for koa2, and followed the examples of the author, but i always get "Unauthorized". I used the console.log and found that it even not hit the serializeUser.
var UserLogin = async (ctx, next) =>{
return passport.authenticate('local', function(err, user, info, status) {
if (user === false) {
ctx.body = { success: false }
} else {
ctx.body = { success: true }
return ctx.login(user)
}
})(ctx, next);
};
And then I searched on the web and found another writing of router, it goes to the serializeUser but the done(null, user.id) threw error that "cannot get id from undefined".
let middleware = passport.authenticate('local', async(user, info) => {
if (user === false) {
ctx.status = 401;
} else {
await ctx.login(ctx.user, function(err){
console.log("Error:\n- " + err);
})
ctx.body = { user: user }
}
});
await middleware.call(this, ctx, next)
The auth.js are showed below. Also I followed koa-passport example from the author here and tried to use session, but every request i sent will get a TypeError said "Cannot read property 'message' of undefined". But I think this is not the core problem of authentication, but for reference if that really is.
const passport = require('koa-passport')
const fetchUser = (() => {
const user = { id: 1, username: 'name', password: 'pass', isAdmin: 'false' };
return async function() {
return user
}
})()
const LocalStrategy = require('passport-local').Strategy
passport.use(new LocalStrategy(function(username, password, done) {
fetchUser()
.then(user => {
if (username === user.username && password === user.password) {
done(null, user)
} else {
done(null, false)
}
})
.catch(err => done(err))
}))
passport.serializeUser(function(user, done) {
done(null, user.id)
})
passport.deserializeUser(async function(id, done) {
try {
const user = await fetchUser();
done(null, user)
} catch(err) {
done(err)
}
})
module.exports = passport;
By the way when I use the simple default one, it will just give me a "Not found". But through console.log I can see it actually got into the loginPass.
var loginPass = async (ctx, next) =>{
passport.authenticate('local', {
successRedirect: '/myApp',
failureRedirect: '/'
});
};
In server.js:
// Sessions
const convert = require('koa-convert');
const session = require('koa-generic-session');
app.keys = ['mySecret'];
app.use(convert(session()));
// authentication
passport = require('./auth');
app.use(passport.initialize());
app.use(passport.session());
Thanks a lot for any help!!! :D

Resources