A logged-in visitor should be able to change their password. Being logged in is not enough proof: somebody at an unlocked computer has the cookie too. So the server asks for the old password first, checks that the new one is long enough, and stores the new hash. Then it logs out every other session of that user, so a cookie left behind on another computer stops working.
express-session keeps every session in a session store, req.sessionStore. Its all method hands your callback every session, keyed by session id, and destroy(sid) removes one. req.sessionID is the id of the session making this request. For example, this route on another path counts a user's sessions:
app.get("/api/me/sessions", requireLogin, (req, res) => {
req.sessionStore.all((err, sessions) => {
let count = 0;
for (const sid in sessions) {
if (sessions[sid].userId === req.user.id) {
count = count + 1;
}
}
res.json({ sessions: count });
});
});
The store answers later, so the response goes inside the callback. for … in walks through an object's keys, which here are the session ids.
The Account page (client/src/pages/AccountPage.jsx, given) sends the form to PUT /api/me/password. It shows an error as an alert and the message as a status. The check logs Ana in on the page and also from another browser. Your server must answer:
PUT /api/me/password {"old_password": "wrong-pass-1", "new_password": "mugs-forever-9"} → 401 {"error": "Wrong password"}
PUT /api/me/password {"old_password": "mug-lover-1", "new_password": "short"} → 400 {"error": "The new password needs at least 8 characters"}
PUT /api/me/password {"old_password": "mug-lover-1", "new_password": "mugs-forever-9"} → 200 {"message": "Password changed"}
GET /api/me (the other browser) → 401 {"error": "Not logged in"}
GET /api/me (this page, after a reload) → 200 (still ana@example.com)
POST /api/login (old password) → 401 {"error": "Wrong email or password"}
POST /api/login (new password) → 200 {"email": "ana@example.com", "role": "customer"}
Your task: in server/app.js, fill in changePassword. Check the old password (401) and the new one (400), store the new hash, destroy the user's other sessions and answer { message: "Password changed" }. Then add the route PUT /api/me/password with requireLogin first.
Assignment
Follow the Coding Tutorial to write changePassword one line at a time and connect it to PUT /api/me/password.
Hintreq.user has no password_hash, so load the whole row with SELECT * first. In the loop, skip req.sessionID and compare sessions[sid].userId with user.id.
Free plan: 30 tutor messages. PRO is unlimited.
