I am currently working on getting a user's session to update following an update request from the client. The idea here is to display the updated user data immediately to the Client after update is succesful. For this I use sessions to store the data instead of having to make a get-request to the database one every refresh.
My issue is that whenever a user updates himself, the session is still keeping the prior value retrieved after login despite me setting it to a new one. So the updateMyProfile request does not save the data in the session. This is something I test with my Authenticate request that is called on refresh to retrieve user data for a currentUser
/Server
app.use(
session({
key: "someID",
secret: "someSecret", //Normally this has to be long and complex for security
resave: false,
rolling: true,
saveUninitialized: false,
cookie: { //How long will the cookie live for?
expires: 60 * 60 * 1000, //Expires after one hour
}
}));
app.patch('/updateMyProfile', verifyJWT, async(req, res) => {
const name = req.body.name;
const email = req.body.email;
const phoneNr = req.body.phoneNr;
const id = req.body.id;
var updated = "UPDATE users set name = ?, email = ?, phoneNr = ? WHERE id = ?;";
var retrieved = "SELECT * FROM users WHERE id = ?;";
db.query(updated, [name, email, phoneNr, id],
(err, result) => {
if (err) {
res.send({message: err}) //Sending error to front-end
console.log(err);
}
if (result) {
db.query(retrieved, id,
(err, resultRetrieved) => {
if (err) {
res.send({message: err}) //Sending error to front-end
console.log(err);
} else {
req.session.user = resultRetrieved; //Session is updated to contain new data!
res.send({user: resultRetrieved, message: "Update succesful!"});
console.log("User is now: " req.session.user[0].name);
res.end();
}
})}
});
});
//This method is called on every refresh on client via the UseEffect function
app.post('/authenticate', (req, res) => { //An endpoint for user-auth
const token = req.body.token;
const userSession = req.session.user;
jwt.verify(token, "jwtSecret", (err, decoded) => {
if (err) {
res.send({auth: false, user: "No valid token!"});
console.log('No valid token');
}
else if (userSession) { //Verified user! < ----------------->
res.send({auth: true, user: userSession});
console.log(userSession[0].name ' is in!');
}
else { //Else if user is not verified, we return an empty object with rejected authentication
res.send({auth: false, user: 'No user session!'});
console.log('No user session');
}
})
});
This is an example from Client on an update request
const update = () => {
Axios.patch("http://localhost:3001/updateMyProfile", {name: name, email: email, phoneNr: phoneNr, id: id},
{headers: {"x-access-token": localStorage.getItem("token")}}
).then(
(response) => {
alert(response.data.message);
}
);
}
CodePudding user response:
The Problem
The code above, while a little unusual in the way it mixes uses of server-side sessions and client-side sessions (JWTs), is not incorrect or broken.
The problem in this case was on the client-side, with the way cookies were handled - meaning that updates seemingly weren't being applied to session data.
The session cookie was being set correctly by the server, and accepted by the client, however was not being included in further requests. This meant that the future requests seemed to have incorrect session data because the server saw each request as a brand new request without a previously existing session. This fact was hidden because the JWT is being used to verify the user is logged in, rather than checking the server-side session.
The Solution
Axios is being used to make requests on the client-side, the requests were not being sent with the appropriate cookie header.
To remediate this, each request should be provided with the withCredentials
option like so:
Axios.patch(address, data, { withCredentials: true }).then(handleResponse);