Skip to content

Commit 7d07beb

Browse files
committed
feat: add zod validation for auth routes
1 parent 7a15543 commit 7d07beb

4 files changed

Lines changed: 62 additions & 4 deletions

File tree

backend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"express-session": "^1.18.1",
2121
"mongoose": "^8.8.2",
2222
"passport": "^0.7.0",
23-
"passport-local": "^1.0.0"
23+
"passport-local": "^1.0.0",
24+
"zod": "^4.4.3"
2425
},
2526
"devDependencies": {
2627
"nodemon": "^3.1.9"

backend/routes/auth.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
const express = require("express");
22
const passport = require("passport");
33
const User = require("../models/User");
4+
const { signupSchema, loginSchema } = require("../validators/authValidator");
5+
const { validateRequest } = require("../validators/validationRequest");
46
const router = express.Router();
57

68
// Signup route
7-
router.post("/signup", async (req, res) => {
9+
router.post("/signup", validateRequest(signupSchema), async (req, res) => {
810

9-
const { username, email, password } = req.body;
11+
const { username, email, password } = req.validated;
1012

1113
try {
1214
const existingUser = await User.findOne( {email} );
@@ -23,7 +25,7 @@ router.post("/signup", async (req, res) => {
2325
});
2426

2527
// Login route
26-
router.post("/login", passport.authenticate('local'), (req, res) => {
28+
router.post("/login", validateRequest(loginSchema), passport.authenticate('local'), (req, res) => {
2729
res.status(200).json( { message: 'Login successful', user: req.user } );
2830
});
2931

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
const { z } = require("zod");
2+
3+
const signupSchema = z.object({
4+
username: z.string()
5+
.min(3, "Username must be at least 3 characters long")
6+
.max(30, "Username must be at most 30 characters long")
7+
.regex(/^[a-zA-Z0-9_]+$/, "Username can only contain letters, numbers, and underscores")
8+
.trim(),
9+
10+
email: z.string()
11+
.email("Invalid email address")
12+
.toLowerCase()
13+
.trim(),
14+
15+
password: z.string()
16+
.min(8, "Password must be at least 8 characters long")
17+
.max(100, "Password must be at most 100 characters long")
18+
.regex(
19+
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/,
20+
'Password must contain uppercase, lowercase, number, and special character'
21+
),
22+
});
23+
24+
25+
const loginSchema = z.object({
26+
email: z.string()
27+
.email("Invalid email address")
28+
.toLowerCase()
29+
.trim(),
30+
password: z.string()
31+
.min(8, "Password must be at least 8 characters long")
32+
.max(100, "Password must be at most 100 characters long")
33+
});
34+
35+
36+
module.exports = { signupSchema, loginSchema };
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const validateRequest = (schema) => (req,res, next) => {
2+
const result = schema.safeParse(req.body);
3+
4+
if(!result.success) {
5+
return res.status(400).json({
6+
success: false,
7+
message: 'Validation failed',
8+
errors: result.error.issues.map((err) => ({
9+
field: err.path.join('.'),
10+
message: err.message,
11+
})),
12+
});
13+
}
14+
15+
req.validated = result.data;
16+
next();
17+
}
18+
19+
module.exports = { validateRequest };

0 commit comments

Comments
 (0)