Skip to content

Commit ae48efd

Browse files
committed
Remove try/catch due to new Express v5 async behaviour
Effectively built-in express-async-handler behaviour now. https://expressjs.com/en/guide/migrating-5.html#rejected-promises
1 parent 7048919 commit ae48efd

File tree

1 file changed

+76
-97
lines changed

1 file changed

+76
-97
lines changed

nodeJS/authentication/sessions.md

Lines changed: 76 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -166,17 +166,12 @@ app.get("/signup", (req, res) => {
166166
res.render("signup");
167167
});
168168

169-
// or use express-async-handler to ditch the try/catch
170169
app.post("/signup", async (req, res, next) => {
171-
try {
172-
await pool.query(
173-
"INSERT INTO users (username, password) VALUES ($1, $2)",
174-
[req.body.username, req.body.password],
175-
);
176-
res.redirect("/");
177-
} catch(err) {
178-
next(err);
179-
}
170+
await pool.query(
171+
"INSERT INTO users (username, password) VALUES ($1, $2)",
172+
[req.body.username, req.body.password],
173+
);
174+
res.redirect("/");
180175
});
181176
```
182177

@@ -199,32 +194,28 @@ app.get("/login", (req, res) => {
199194
});
200195

201196
app.post("/login", async (req, res, next) => {
202-
try {
203-
// query for a matching username
204-
const { rows } = await pool.query(
205-
"SELECT * FROM users WHERE username = $1",
206-
[req.body.username],
207-
);
208-
const user = rows[0];
209-
210-
// if the user exists and the password matches...
211-
if (user?.password === req.body.password) {
212-
// serialize the user ID in the session object so it can be retrieved later
213-
req.session.userId = user.id;
214-
req.session.save((err) => {
215-
if (err) {
216-
next(err);
217-
} else {
218-
res.redirect("/");
219-
}
220-
});
221-
} else {
222-
res.render("login", {
223-
error: "Incorrect username or password",
224-
});
225-
}
226-
} catch(err) {
227-
next(err);
197+
// query for a matching username
198+
const { rows } = await pool.query(
199+
"SELECT * FROM users WHERE username = $1",
200+
[req.body.username],
201+
);
202+
const user = rows[0];
203+
204+
// if the user exists and the password matches...
205+
if (user?.password === req.body.password) {
206+
// serialize the user ID in the session object so it can be retrieved later
207+
req.session.userId = user.id;
208+
req.session.save((err) => {
209+
if (err) {
210+
next(err);
211+
} else {
212+
res.redirect("/");
213+
}
214+
});
215+
} else {
216+
res.render("login", {
217+
error: "Incorrect username or password",
218+
});
228219
}
229220
});
230221
```
@@ -295,27 +286,23 @@ As of now, our `GET /` route will always display the homepage and will crash if
295286
296287
```javascript
297288
async function checkAuthenticated(req, res, next) {
298-
try {
299-
if (!req.session.userId) {
300-
res.redirect("/login");
301-
return;
302-
}
303-
304-
// if there is a user ID in the session, grab that matching user
305-
const { rows } = await pool.query(
306-
"SELECT * FROM users WHERE id = $1",
307-
[req.session.userId],
308-
);
309-
// add the user details we need to req
310-
// so we can access it in the next middleware
311-
req.user = {
312-
id: rows[0].id,
313-
username: rows[0].username,
314-
};
315-
next();
316-
} catch (err) {
317-
next(err);
289+
if (!req.session.userId) {
290+
res.redirect("/login");
291+
return;
318292
}
293+
294+
// if there is a user ID in the session, grab that matching user
295+
const { rows } = await pool.query(
296+
"SELECT * FROM users WHERE id = $1",
297+
[req.session.userId],
298+
);
299+
// add the user details we need to req
300+
// so we can access it in the next middleware
301+
req.user = {
302+
id: rows[0].id,
303+
username: rows[0].username,
304+
};
305+
next();
319306
}
320307
```
321308
@@ -371,54 +358,46 @@ npm install argon2
371358
const argon2 = require("argon2");
372359

373360
app.post("/signup", async (req, res, next) => {
374-
try {
375-
const hashedPassword = await argon2.hash(req.body.password);
376-
await pool.query(
377-
"INSERT INTO users (username, password) VALUES ($1, $2)",
378-
[req.body.username, hashedPassword],
379-
);
380-
res.redirect("/");
381-
} catch(err) {
382-
next(err);
383-
}
361+
const hashedPassword = await argon2.hash(req.body.password);
362+
await pool.query(
363+
"INSERT INTO users (username, password) VALUES ($1, $2)",
364+
[req.body.username, hashedPassword],
365+
);
366+
res.redirect("/");
384367
});
385368
```
386369
387370
We don't need to modify any of its options, as the defaults all meet the [password storage recommendations set by OWASP](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#introduction) (Open Worldwide Application Security Project). Now in our `POST /login` middleware, we can also use argon2 to verify the submitted password against the stored salted hash:
388371
389372
```javascript
390373
app.post("/login", async (req, res, next) => {
391-
try {
392-
const { rows } = await pool.query(
393-
"SELECT * FROM users WHERE username = $1",
394-
[req.body.username],
395-
);
396-
const user = rows[0];
397-
398-
// argon2.verify requires an argon2 hash as its first arg
399-
// so we can't just pass in `undefined` if no user exists.
400-
// The hash itself doesn't matter as long as it's a valid argon2 hash
401-
// since this is to prevent timing attacks if no user is found
402-
const isMatchingPassword = await argon2.verify(
403-
user?.password ?? process.env.FALLBACK_HASH,
404-
req.body.password,
405-
);
406-
if (user && isMatchingPassword) {
407-
req.session.userId = user.id;
408-
req.session.save((err) => {
409-
if (err) {
410-
next(err);
411-
} else {
412-
res.redirect("/");
413-
}
414-
});
415-
} else {
416-
res.render("login", {
417-
error: "Incorrect username or password",
418-
});
419-
}
420-
} catch(err) {
421-
next(err);
374+
const { rows } = await pool.query(
375+
"SELECT * FROM users WHERE username = $1",
376+
[req.body.username],
377+
);
378+
const user = rows[0];
379+
380+
// argon2.verify requires an argon2 hash as its first arg
381+
// so we can't just pass in `undefined` if no user exists.
382+
// The hash itself doesn't matter as long as it's a valid argon2 hash
383+
// since this is to prevent timing attacks if no user is found
384+
const isMatchingPassword = await argon2.verify(
385+
user?.password ?? process.env.FALLBACK_HASH,
386+
req.body.password,
387+
);
388+
if (user && isMatchingPassword) {
389+
req.session.userId = user.id;
390+
req.session.save((err) => {
391+
if (err) {
392+
next(err);
393+
} else {
394+
res.redirect("/");
395+
}
396+
});
397+
} else {
398+
res.render("login", {
399+
error: "Incorrect username or password",
400+
});
422401
}
423402
});
424403
```

0 commit comments

Comments
 (0)