Home > Back-end >  Why can't I store my session in Express.js (MERN Stack)?
Why can't I store my session in Express.js (MERN Stack)?

Time:01-22

I've been trying to store a user's email in the session for my express.js file. But everytime I try something, and call another function, the session remains undefined. Been working on this for weeks now, and I can't seem to find the answer.

server.js file:

import express from 'express';
import cookieParser from 'cookie-parser';
import session from 'express-session';
const app = express();
app.use(cookieParser());
app.use(session({
    secret: 'keyboard cat',
    resave: false,
    saveUninitialized: true,
    cookie: {
        maxAge  : 1000 * 60 * 60 * 3, // if 1 day * 24 but since *3 its for 3 hours only
    },
}))

app.post('/user/login', (req, res) => { 
    const loginUser = req.body;
    const email = loginUser['email'];
    const password = loginUser['password'];
    if (!email || !password){ 
        res.status(400).json({success: false, error: "Please provide email and password"});
    }
    try { 
        Users.findOne({ email: email }, (err, user) => { 
            if (password == user['password']){
                req.session.user(user['email']);
                res.status(200).send(user_email);
            } else {
                res.status(400).json({success: false, error: "incorrect password"});
            }
        });
    } catch { 
    }
})

Calling the Login file from the frontend (react js)

import React, { useState } from 'react';
import { Grid, TextField, Button } from '@mui/material';
import "./SignUpLogin.css";
import axios from '../../axios';
import useForm from './useForm';
import { Form } from './useForm';


const initialValues = { 
    email: '',
    password: ''
}

function Login({ modalFunc }) { 

    const LoginUser = e => { 
        console.log("INSIDE LOGIN USER");
        modalFunc();
        e.preventDefault();
        axios.post('/user/login', values, {withCredentials: true})
            .then(response => { 
                console.log("in login user");
                console.log(response.data);
            })
    }

    const {
        values, 
        setValues, 
        handleInputChange
    } = useForm(initialValues);

    return (
        <div className="Login">
            <Form> 
                <Grid item>
                    <TextField
                        required 
                        variant="outlined"
                        label="Email"
                        name="email"
                        color="secondary"
                        fullWidth
                        value={ values.email } 
                        onChange={ handleInputChange }
                    />
                </Grid>
                <Grid item>
                    <TextField 
                    required 
                        variant="outlined"
                        label="Password"
                        name="password"
                        type="password"
                        color="secondary"
                        fullWidth
                        value={ values.password }
                        onChange={ handleInputChange }
                    />
                </Grid>
                <Grid item> 
                    <Button 
                        variant="contained"
                        fullWidth
                        onClick = { LoginUser }>
                    Login
                    </Button>
                </Grid>
            </Form>
        </div>
    )
}

export default Login

But when I call server.js again in another get function, session is undefined.

app.get('/user/loggedIn', (req, res) => { 
    console.log(req.session.user);
    user_email = req.session.user;
    if (req.session.user) {
        Users.findOne({ email: user_email }, (err, user) => { 
            // console.log("in logged in, in server!!!");
            // console.log(user);
            res.status(200).send(user);
        })
    } else { 
        console.log("no session");
        res.status(400);
    }
})

Calling app.get('/user/loggedIn') in react.js file:

function Header() {
  const [modalOpen, setModalOpen] = useState(false); 
  const changeModal = () => { 
    setModalOpen(!modalOpen)
  }

  const [user, setUser] = useState(null);
  useEffect(() => { 
    // axios.get('/user/loggedIn', {}, {withCredentials: true})
    axios.get('/user/loggedIn', {}, {withCredentials: true})
    .then(response => { 
      // console.log("RESPONSE FROM LOGGED IN");
      // console.log(response.data);
      setUser(response.data);
    })
  })

CodePudding user response:

Here is my working solution,

const bodyParser = require('body-parser');
const MongoStore = require('connect-mongo');
const cors = require('cors');
const express = require('express');
const { connect } = require('mongoose');
const UserModel = require('./models/UserMode');
const session = require('express-session');
(async () => {
  try {
    let response = await connect('mongodb://localhost:27017/test');
    console.log('connected');
  } catch (error) {
    console.log(error);
  }
})();
const app = express();
app.all('/*', function (req, res, next) {
  res.header('Access-Control-Allow-Credentials', true); //this is you are missing
  next();
});
const corsOpts = {
  origin: ['http://localhost:3001'], // you have to provide list of whitelisted urls. In this case url of your frontend react app. 
                                      //you cant use * because you are using {withCredentials: true} in axios
  methods: ['GET', 'POST'],   
  allowedHeaders: ['Content-Type'],
};
app.use(cors(corsOpts)); //this is you are missing
app.use(bodyParser.json());
app.use(
  session({
    cookie: { secure: false, httpOnly: false },
    secret: 'Your_Secret_Key',
    resave: true,
    saveUninitialized: true,
    name: 'some name',
    store: MongoStore.create({
      mongoUrl: 'mongodb://localhost:27017/test', // you have to provide some storage to store session data
    }),
  })
);
app.get('/login_check', async (req, res) => {
  console.log(req.session); // just check if session is getting stored or not
  res.json('check');
});
app.post('/login', async (req, res) => {
  try {
    const { email, password } = req.body;
    let userDetails = await UserModel.findOne({ email, password });
    req.session.user = userDetails; // here pass any details that you want to send to session
    console.log(userDetails);
    res.send(userDetails);
  } catch (error) {
    console.log(error);
    res.status(500);
  }
});

const server = app.listen(5000, () =>
  console.log(`Server started on port ${5000}`)
);

Also couple of things that you are doing wrong, after this line

res.status(400).json({success: false, error: "Please provide email and password"});

you should write it this way, or else it would throw an error.

 return res.status(400).json({success: false, error: "Please provide email and password"});
    // or this way
 res.status(400).json({success: false, error: "Please provide email and password"});
    return;

CodePudding user response:

Here is the clean solution:

first you've to import 2 packages and add those line of code in server.js file:

const session = require('express-session');
const MongoSessionStore = require('connect-mongodb-session')(session);


const MongoDBStore = new MongoSessionStore({
  uri: process.env.MONGODB_URL,
  collection: 'sessions',
});

app.use(
  session({
    secret: 'my-secret',
    resave: false,
    saveUninitialized: false,
    store: MongoDBStore,
  })

);

then store the session in this route:

app.post('/user/login', (req, res) => {
     req.session.user = user;
 }
  •  Tags:  
  • Related