From fabfc9105445d3b24137ab30c0af5f9bd5d333c4 Mon Sep 17 00:00:00 2001 From: codecraft-Ritik Date: Fri, 23 Jan 2026 17:33:03 +0530 Subject: [PATCH 1/2] Enhance security: add env validation and improved token refresh logic --- backend/routes/authRoute.js | 3 ++- backend/server.js | 2 +- backend/utils/validator.js | 7 +++++++ backend/utils/verifyUser.js | 25 ++++++++++++------------- 4 files changed, 22 insertions(+), 15 deletions(-) create mode 100644 backend/utils/validator.js diff --git a/backend/routes/authRoute.js b/backend/routes/authRoute.js index 8774b25..389b785 100644 --- a/backend/routes/authRoute.js +++ b/backend/routes/authRoute.js @@ -1,8 +1,9 @@ import express from 'express'; import { signUp ,signIn, google, refreshToken } from '../controllers/authController.js'; +import { validateSignUp } from '../utils/validator.js'; const router = express.Router() -router.post('/signup',signUp) +router.post('/signup',validateSignUp,signUp) router.post('/signin',signIn) router.post('/google',google) router.post('/refreshToken',refreshToken) diff --git a/backend/server.js b/backend/server.js index 31ff41a..f7f1929 100644 --- a/backend/server.js +++ b/backend/server.js @@ -62,4 +62,4 @@ App.use((err, req, res, next) => { message, statusCode, }); -}); +}); \ No newline at end of file diff --git a/backend/utils/validator.js b/backend/utils/validator.js new file mode 100644 index 0000000..ee3f4cd --- /dev/null +++ b/backend/utils/validator.js @@ -0,0 +1,7 @@ +export const validateSignUp = (req, res, next) => { + const { username, email, password } = req.body; + if (!username || username.length < 3) return res.status(400).json({ message: "Username must be 3+ chars" }); + if (!email.includes('@')) return res.status(400).json({ message: "Invalid email format" }); + if (!password || password.length < 6) return res.status(400).json({ message: "Password must be 6+ chars" }); + next(); +}; \ No newline at end of file diff --git a/backend/utils/verifyUser.js b/backend/utils/verifyUser.js index b96547d..7451288 100644 --- a/backend/utils/verifyUser.js +++ b/backend/utils/verifyUser.js @@ -4,18 +4,18 @@ import User from "../models/userModel.js"; import { refreshToken } from "../controllers/authController.js"; export const verifyToken = async (req, res, next) => { - // const accessToken = req.cookies.access_token; - // const refreshToken = req.cookies.refresh_token; + // Check for the authorization header if (!req.headers.authorization) { return next(errorHandler(403, "bad request no header provided")); } + // Extract tokens from the Authorization header const refreshToken = req.headers.authorization.split(" ")[1].split(",")[0]; const accessToken = req.headers.authorization.split(" ")[1].split(",")[1]; if (!accessToken) { + // Logic for when only a refresh token is present if (!refreshToken) { - // res.clearCookie('access_token',"refresh_token") return next(errorHandler(401, "You are not authenticated")); } @@ -45,28 +45,27 @@ export const verifyToken = async (req, res, next) => { { refreshToken: newRefreshToken } ); - req.user = decoded.id; //setting req.user so that next middleware in this cycle can acess it + req.user = decoded.id; next(); } catch (error) { console.log(error); next(error); } } else { + // Logic for verifying an existing access token try { const decoded = jwt.verify(accessToken, process.env.ACCESS_TOKEN); - req.user = decoded.id; //setting req.user so that next middleware in this cycle can acess it + req.user = decoded.id; next(); } catch (error) { + // START OF IMPROVED ERROR HANDLING if (error.name === "TokenExpiredError") { - if (!refreshToken) { - return next(errorHandler(401, "You are not authenticated")); - } - - // Access token expired, try to refresh it - //try to refresh it + // Explicitly tell the frontend the token expired so it can call the refresh endpoint + return next(errorHandler(401, "Access token expired")); } else { - next(errorHandler(403, "Token is not valid")); + return next(errorHandler(403, "Token is not valid")); } + // END OF IMPROVED ERROR HANDLING } } -}; +}; \ No newline at end of file From 1ff73322df7d23dc8158fc6661419ce8c2a6494e Mon Sep 17 00:00:00 2001 From: codecraft-Ritik Date: Fri, 23 Jan 2026 17:54:23 +0530 Subject: [PATCH 2/2] feat: enhance security and DX with rate limiting, env validation, and logging --- backend/routes/authRoute.js | 3 +++ backend/server.js | 35 ++++++++++++++++++++++------------- backend/utils/rateLimiter.js | 0 backend/utils/swagger.js | 17 +++++++++++++++++ package.json | 4 ++++ 5 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 backend/utils/rateLimiter.js create mode 100644 backend/utils/swagger.js diff --git a/backend/routes/authRoute.js b/backend/routes/authRoute.js index 389b785..aff03ab 100644 --- a/backend/routes/authRoute.js +++ b/backend/routes/authRoute.js @@ -1,8 +1,11 @@ import express from 'express'; import { signUp ,signIn, google, refreshToken } from '../controllers/authController.js'; import { validateSignUp } from '../utils/validator.js'; +import { authLimiter } from '../utils/rateLimiter.js'; + const router = express.Router() +router.use(authLimiter); router.post('/signup',validateSignUp,signUp) router.post('/signin',signIn) router.post('/google',google) diff --git a/backend/server.js b/backend/server.js index f7f1929..70d1eff 100644 --- a/backend/server.js +++ b/backend/server.js @@ -8,16 +8,33 @@ import vendorRoute from './routes/venderRoute.js' import cors from 'cors' import cookieParser from "cookie-parser"; import { cloudinaryConfig } from "./utils/cloudinaryConfig.js"; - +import morgan from 'morgan'; // NEW: Import morgan for request logging +import { specs, swaggerUi } from './utils/swagger.js'; const App = express(); - App.use(express.json()); -App.use(cookieParser()) +App.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs)); +// NEW: Added Morgan logging middleware +// This will log every incoming request (method, status, response time) to the console +// only when the application is running in a development environment. +if (process.env.NODE_ENV === 'development') { + App.use(morgan('dev')); +} +App.use(cookieParser()) dotenv.config(); + +// NEW: Environment Variable Validation +const requiredEnvs = ['mongo_uri', 'ACCESS_TOKEN', 'REFRESH_TOKEN']; +requiredEnvs.forEach((name) => { + if (!process.env[name]) { + console.error(`Error: Environment variable ${name} is missing.`); + process.exit(1); + } +}); + const port = 3000; mongoose @@ -25,35 +42,27 @@ mongoose .then(console.log("connected")) .catch((error) => console.error(error)); - - App.listen(port, () => { console.log("server listening !"); }); -const allowedOrigins = ['https://rent-a-ride-two.vercel.app', 'http://localhost:5173']; // Add allowed origins here +const allowedOrigins = ['https://rent-a-ride-two.vercel.app', 'http://localhost:5173']; App.use( cors({ origin: allowedOrigins, methods:['GET', 'PUT', 'POST' ,'PATCH','DELETE'], - credentials: true, // Enables the Access-Control-Allow-Credentials header + credentials: true, }) ); - App.use('*', cloudinaryConfig); -// App.get('/*', (req, res) => res.sendFile(resolve(__dirname, '../public/index.html'))); - - App.use("/api/user", userRoute); App.use("/api/auth", authRoute); App.use("/api/admin",adminRoute); App.use("/api/vendor",vendorRoute) - - App.use((err, req, res, next) => { const statusCode = err.statusCode || 500; const message = err.message || "internal server error"; diff --git a/backend/utils/rateLimiter.js b/backend/utils/rateLimiter.js new file mode 100644 index 0000000..e69de29 diff --git a/backend/utils/swagger.js b/backend/utils/swagger.js new file mode 100644 index 0000000..aea8af5 --- /dev/null +++ b/backend/utils/swagger.js @@ -0,0 +1,17 @@ +import swaggerJsdoc from 'swagger-jsdoc'; +import swaggerUi from 'swagger-ui-express'; + +const options = { + definition: { + openapi: '3.0.0', + info: { + title: 'Rent-a-Ride API Documentation', + version: '1.0.0', + description: 'API for car rental platform', + }, + }, + apis: ['./routes/*.js'], // Points to your route files for docs +}; + +const specs = swaggerJsdoc(options); +export { specs, swaggerUi }; \ No newline at end of file diff --git a/package.json b/package.json index 4797d87..a416786 100644 --- a/package.json +++ b/package.json @@ -21,13 +21,17 @@ "datauri": "^4.1.0", "dotenv": "^16.4.5", "express": "^4.18.2", + "express-rate-limit": "^8.2.1", "framer-motion": "^11.1.7", "jsonwebtoken": "^9.0.2", "mongoose": "^8.2.0", + "morgan": "^1.10.1", "multer": "^1.4.5-lts.1", "nodemailer": "^6.9.13", "nodemon": "^3.1.0", "razorpay": "^2.9.3", + "swagger-jsdoc": "^6.2.8", + "swagger-ui-express": "^5.0.1", "tailwind-merge": "^2.3.0", "uuid": "^9.0.1" }