Session not saving after login - node.js

I have a problem with express-session. When I try to login I have to save my userdata in cookies and after redirect get it on home page. Now after redirect my cookie is clearing and I have default cookie without some data
const authRoute = require('./routes/auth')
mongoose.connect(
process.env.DB_CONNECT,
{ useUnifiedTopology: true, useNewUrlParser: true },
() => {
console.log('Connected to DB')
});
//Middleware
app.use(express.json())
app.use(cors())
app.use(session({
name: 'sid',
resave: false,
saveUninitialized: false,
store: new MongoStore({ mongooseConnection: mongoose.connection }),
secret: process.env.SESS_SECRET,
cookie: {
maxAge: 1000 * 60 * 60 * 2,
sameSite: true,
secure: false
}
}))
app.use('/api/user', authRoute)
Routes file
router.get('/login', (req, res) => {
console.log(req.session);
if (req.session.user) {
res.status(200).send(req.session.user)
} else res.status(403).send({ error: 'You need to login first' })
})
router.post('/login', async (req, res) => {
...
req.session.user = { id: user._id, username: user.name, email: user.email }
req.session.save()
//CREATE AND ASSIGN TOKER
const token = jsw.sign({ _id: user._id }, process.env.TOKEN_SECRET)
res.header('auth-toker', token).send(user)
})

Try disabling the Windows Defender or other anti virus software. Those may not allow the connection to go through

Related

Correct session settings for Google cloud express app doesnt work in production using passport

Problem: Everything works fine in development but also in the normal google chrome browser. However when I try incognito and Firefox it sends two different session ids. I cant find a good reason why the session ID changes on the callback URL. I can see that the correct information gets stored, but when a user logs in on firefox the session key is different when the user is on the callback URL than what it is when the user on the home page. The key is however the same everytime I refresh the site but this does not help me as during login the session key is wrong. As I said it works perfect in development.
I have activated withCredentials on the front end.
I am just super confused as it works fine on google chrome but not on anything else.
Here is my code:
Server.js
... //a bunch of imports
app.use(cors(corsOptions));
//SESSION SETUP TOOLS
app.use(cookieParser());
app.use(express.json())
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.json())
//DDOS PROTECTION
app.use(compression())
app.use(helmet())
app.use(limiter);
//SESSION SETTINGS
app.set('trust proxy', true);
app.enable('trust proxy')
const sessionMemStore = () => {
if (isProduction) {
const firestore = new FirestoreStore({
dataset: new Firestore(),
kind: 'express-sessions',
});
return firestore
}
else {
return null
}
};
app.use(
session({
...sessionSettings,
store: sessionMemStore()
})
);
passport.serializeUser((user, done) => {
done(null, user);
});
passport.deserializeUser((user, done) => {
done(null, user);
});
// Initiate Strategy
passport.use(
new SteamStrategy(
{
returnURL: BACKEND_URL + "/api/auth/steam/return",
realm: BACKEND_URL,
apiKey: "B14DD3E47A70AC859EE73AB2C656CB34",
},
function (identifier, profile, done) {
process.nextTick(function () {
profile.identifier = identifier;
return done(null, profile);
});
}
)
);
app.use(passport.initialize());
app.use(passport.session());
app.get(
"/api/v1/auth/steam",
passport.authenticate("steam", { failureRedirect: FRONTEND_URL + "/tos" }),
function (req, res) {
res.send(req.user);
}
);
app.get(
"/api/auth/steam/return",
passport.authenticate("steam", { failureRedirect: FRONTEND_URL + "/tos" }),
function (req, res) {
logon(req.user);
req.session.steamuser = req.user;
res.redirect(FRONTEND_URL);
}
);
app.listen(port, () => {
console.log("Listening, port " + port);
});
sessionsettings.
const sessionSettings = {
secret: "someRandomKey",
saveUninitialized: true,
resave: false,
cookie: {
maxAge: 24 * 60 * 60 * 1000, httpOnly: true, secure: true, sameSite: isProduction ? "none" : "lax"
},
name: "session"
};

Express-session creates new session every request

I put my node express server into production. In development, express-session worked fine (it stored session into cookies with MemoryStore). But now it creates a new session ID into MongoStore every time I refresh or make a request. Also, it doesn't create a cookie in the browser anymore (idk if it's a good or a bad thing)
Most StackOverflow queries on this topic tell me to do things that I've already done so no help there
Here is my express and session setup:
const app = express()
const apiPort = process.env.PORT || process.env.API_PORT
app.use(cors({credentials: true, origin: process.env.ORIGIN_URL}))
mongoose.connection.on('error', (err) => {
console.error(err);
console.log('MongoDB connection error. Please make sure MongoDB is running.');
process.exit();
});
const sessionMiddleware = session({
resave: false,
saveUninitialized: false,
secret: process.env.SECRET,
// secure: true,
cookie: {
sameSite: true,
httpOnly: true,
secure: true,
maxAge: 1000 * 60 * 60 * 24 * 30
},
store: MongoStore.create({
mongoUrl: process.env.MONGODB_URI
})
})
app.use(sessionMiddleware);
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static("public"));
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json())
app.post('/auth/login', (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if (err) { return next(err); }
if (info) {
return res.status(401).json({error: info.msg})
}
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.status(200).send(user);
});
})(req, res, next);
});
app.get('/auth/logout', (req, res) => {
req.logout()
res.sendStatus(200)
});
app.get('/checkToken', authCheck, (req, res) => {
res.status(200).send({accountType: res.accountType});
})
Additional info that might be handy for this problem: the front-end is on a separate domain, the aforementioned server is on Heroku, and the DB is in MongoDB cloud.
Turns out all I was missing was app.set('trust proxy', 1) in my setup and sameSite: 'none' in cookie: {} in session middleware.

How to send express-session to client not in same url?

Can I please get some help, I have been searching all over the internet for this and I cannot seem to find the answer that I am looking for.
So I would love to implement expression-session and mongoDB as the store, so session creation I managed to get that done and also saving the session within the store i.e MongoDB managed to get that done.
The problem now comes to when I have to send the session cookie to the client, so I have my server(NodeJS) running on port 5000 and I have the client(ReactJS) running on port 3000, so now how can I send that cookie to the client and flag it as httpOnly cookie?
This is how I tried to setup express-session
mongoose
.connect(MongoURI, {
useNewUrlParser: true,
useCreateIndex: true
})
.then(() => console.log("MongoDB connected..."))
.catch((err) => console.log(err));
const mongoDBstore = new MongoDBStore({
uri: MongoURI,
collection: "mySessions"
});
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
app.use(
session({
name: COOKIE_NAME,
secret: 'SESS_SECRET',
resave: true,
saveUninitialized: false,
store: mongoDBstore,
cookie: {
maxAge: 1000 * 60 * 60 * 3,
sameSite: false,
secure: false
}
})
);
This is where I wanted to send the cookie once user logs in
router.post("/login", (req, res) => {
const { email, password } = req.body;
if (!email || !password) {
return res.status(400).json({ msg: "Please enter all fields" });
}
User.findOne({ email }).then((user) => {
if (!user) return res.status(400).json({ msg: "User does not exist" });
bcrypt.compare(password, user.password).then((isMatch) => {
if (!isMatch) return res.status(400).json({ msg: "Invalid credentials" });
const sessUser = { id: user.id, name: user.name, email: user.email };
req.session.user = sessUser;
res.json({ msg: " Logged In Successfully", sessUser });
});
});
});

How can I use session variables across whole app

I'd like to access session variables assigned just after login further in mysql queries on different path. However when I do that what I receive is "undefined" value. Here's my login script.
users.post('/login', (req, res) => {
User.findOne({
where: {
email: req.body.email
}
})
.then(user => {
if (user) {
if (bcrypt.compareSync(req.body.password, user.password)) {
let token = jwt.sign(user.dataValues, process.env.SECRET_KEY, {
expiresIn: 1440
})
req.session.Osoba=user.Osoba
res.send(token)
}
} else {
res.status(400).json({ error: 'Taki użytkownik nie istnieje' })
}
})
.catch(err => {
res.status(400).json({ error: err })
})
})
Here's session middleware (it's actually at the beggining of the main node file, just after requiring all packages and before any routes):
app.use(session({
secret: 'secret',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}))
Here's the line which gives me undefined.
app.get('/wypozyczanie', async (req, res) => {
if (req.session) {console.log(req.session.Osoba)}
})
Try your session middleware as bellow.
app.use(session({
key: 'sess_key',
secret: 'secret',
saveUninitialized: true,
resave: true,
rolling: true,
cookie: {
expires: 3600000, //1 hour. Sewt as you want
secure: false
}
}));
Make sure req.session.Osoba is assigned before you are using it.

Logout issue with PassportJs / Oauth / GoogleStrategy

I am writing an application using Nodejs and passportjs with Google Strategy. After logging out, the user is still able to login again without entering credentials. How can the user be made to enter credentials again? This can be a big issue on shared computers.
The front end is built using create-react-app that runs on port 3000. For requests related to authentication, a proxy running on port 5000(nodejs server) is used. The code given below is hosted on port 5000
app.use(
session({
cookie: {maxAge: 30 * 24 * 60 * 60 * 1000},
secret: [keys.cookieKey],
resave: false,
saveUninitialized: false
})
);
app.use(cookieParser());
app.use(passport.initialize());
app.use(passport.session());
passport.use(
new GoogleStrategy(
{
clientID: googleClientID,
clientSecret: googleClientSecret,
callbackURL: '/auth/google/callback',
proxy: true
},
async (accessToken, refreshToken, profile, done) => {
const existingUser = await User.findOne({googleId: profile.id});
if(existingUser){
return done(null, existingUser);
}
const user = await new User({ googleId : profile.id}).save();
done(null, user);
}
)
);
app.get('/api/logout', (req, res) => {
console.log(req.user.accessToken);
if(req.session.passport){ delete req.session.passport; }
req.session.destroy(function (err) {
req.logout();
req.logOut();
req.user = null;
res.clearCookie('connect.sid');
res.redirect('/');
});
});
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
["/api", "/auth/google"],
createProxyMiddleware({
target: "http://localhost:5000",
})
);
};
For advanced configurations like logout, passport,a proper session configuration is the key:
Try with this:
app.use(session({
secret: "changeme",
resave: true,
saveUninitialized: true,
rolling: true,
cookie: {
secure: false,
maxAge: (5 * 1000)
}
}));
This was used in
https://github.com/utec/geofrontend-server
A mini server implementation for client side javascript applications, like your react app. I think it will useful for you. Also you can customize the security!

Resources