EDIT - I no longer think it is a development environment issue as the same thing persists in production.
First off, appreciate anytime spent on this - I know that this is a commonly asked question, but I've perused so many questions and tried applying so many of the solutions to no avail.
To summarize, I currently have a React Front-end that is sending request with the Fetch API to my Express server. I want to use express-sessions to save my logged in user information for the session to use and authenticate as the user uses the application.
I'm having this weird issue where every time a new request is sent, the cookie in my browser in the application tab gets set to something completely new. I might be understanding this wrong, but I thought that that was supposed to remain consistent throughout the session, but it doesn't seem to be the case. This is making it so that every time I call a new request, req.session is completely reset with nothing.
Here is some code from my application:
Express- server.js [my setup for express-session and cors]
app.use(cors({
credentials: true
}))
const session = require('express-session')
// Middleware for creating sessions and session cookies.
// A session is created on every request
app.use(session({
secret: 'tis a secret mate',
cookie: {
expires: 3000, // expires in 15 mins
httpOnly: true,
secure: false,
},
// Session saving options
saveUnintialized: false, // don't save the initial session if the session object is unmodified (i.e the user did not log in)
resave: true, // don't resave a session that hasn't been modified
store: MongoStore.create({
mongoUrl: process.env.MONGODB_URI_SESSIONS
})
}))
app.use(function (req, res, next) {
console.log('SESSION LOGGING MIDDLEWARE')
console.log(req.session);
next()
});
app.use((req, res, next) => {
res.header('Access-control-Allow-Origin', 'http://localhost:3000');
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept, Authorization"
);
res.header('Access-Control-Allow-Credentials', true);
next();
});
EDIT - Login Route
app.post('/api/users/login', async (req, res) => {
// pull out the body
const body = req.body
// pull out the username and password
const username = body.username
const password = body.password
User.findByUsernamePassword(username, password)
.then(user => {
// if we find the user, the users information to the session to retain all that information
// will create a function to ensuree that the session exists to make sure that we are logged in
req.session.user = user
req.session.username = user.username
req.session.save()
console.log(req.session)
res.send({ user: req.session.user })
})
.catch(error => {
res.status(400).send()
});
})
Front-end Fetch Calls In the code below, I pasted my login and check-session calls to their respective endpoints. Essentially the check session call just returns what is in the session, and the login call is supposed to login the user and add the user to req.session.user
After logging in, I try to run check-session to see if the user is in the session, but it is not there every time. I also notice that the cookie in my applications tab for chrome changes to something else.
export const login = (username, password, setUser) => {
const obj = {
username: username,
password: password
}
const request = new Request(`${API_HOST}/api/users/login`, {
method: "POST",
credentials: "include",
body: JSON.stringify(obj),
headers: {
"Content-Type": "application/json"
}
})
// send the request
const promise = fetch(request)
.then(res => {
if (res.status === 200) {
return res.json();
}
})
.then(json => {
// if the user exists, setUser to user
console.log("USER PRE:", json.user)
if (json.user !== undefined) {
console.log("USER: ", json.user)
setUser(json.user)
return json.user
}
})
.catch(error => {
console.log(error);
})
return promise
}
export const checkSession = () => {
const url = `${API_HOST}/api/users/check-session`
fetch(url, {
credentials: 'include'
})
.then(res => {
if (res.status === 200) {
console.log('200')
console.log(res.json())
} else {
console.log(res)
}
})
// .then(json => {
// if (json) {
// setUser(json)
// }
// })
.catch(error => {
console.log(error);
});
}
Things I've Tried
Additional notes that might be helpful
Thank you for your time, I know this is a super long question. Please let me know if there is anything else I could provide to help clarify if you want to help!
If you're running the backend and frontend on different hosts, there could be a CORS problem. Also you said that you checked the cookie in the application tab, but if you haven't tried looking at the request and response cookie headers in the network tab, you should check those out to further diagnose the problem. The cookie should be set on the authentication request, and it should be included in the requests following that.