From 260f5fd7e752a105b406ce5724eaefc4df76ad33 Mon Sep 17 00:00:00 2001 From: Priyansh Narang <145008344+priyansh-narang2308@users.noreply.github.com> Date: Wed, 7 Jan 2026 02:46:26 +0530 Subject: [PATCH 1/3] feat: add custom authentication template with JWT and MongoDB --- bin/configs.js | 10 ++++ templates/express_auth/.env | 6 ++ templates/express_auth/config/authConfig.js | 15 +++++ .../express_auth/connection/connection.js | 14 +++++ .../express_auth/controller/authController.js | 57 +++++++++++++++++++ templates/express_auth/index.js | 36 ++++++++++++ templates/express_auth/logs/initLog.js | 7 +++ .../express_auth/middleware/authMiddleware.js | 26 +++++++++ templates/express_auth/models/User.js | 36 ++++++++++++ templates/express_auth/package.json | 24 ++++++++ templates/express_auth/router/authRouter.js | 16 ++++++ 11 files changed, 247 insertions(+) create mode 100644 templates/express_auth/.env create mode 100644 templates/express_auth/config/authConfig.js create mode 100644 templates/express_auth/connection/connection.js create mode 100644 templates/express_auth/controller/authController.js create mode 100644 templates/express_auth/index.js create mode 100644 templates/express_auth/logs/initLog.js create mode 100644 templates/express_auth/middleware/authMiddleware.js create mode 100644 templates/express_auth/models/User.js create mode 100644 templates/express_auth/package.json create mode 100644 templates/express_auth/router/authRouter.js diff --git a/bin/configs.js b/bin/configs.js index 1947a84c..1dd0223c 100644 --- a/bin/configs.js +++ b/bin/configs.js @@ -153,4 +153,14 @@ export const templates = { name: "express_oauth_google", serverPort: "8080:8080", }, + express_auth: { + name: "express_auth", + isUrl: true, + needDB: true, + dbPort: "27017:27017", + dbName: "MongoDB", + serverPort: "8080:8080", + dbDockerImage: "mongo:latest", + dbDataPath: "/data/db", + }, }; diff --git a/templates/express_auth/.env b/templates/express_auth/.env new file mode 100644 index 00000000..721e3436 --- /dev/null +++ b/templates/express_auth/.env @@ -0,0 +1,6 @@ +PORT=8080 +DB_HOST=127.0.0.1 +DB_PORT=27017 +DB_NAME=auth_db +JWT_SECRET=your_secret_jwt_key_here +JWT_EXPIRES_IN=1d diff --git a/templates/express_auth/config/authConfig.js b/templates/express_auth/config/authConfig.js new file mode 100644 index 00000000..db472f24 --- /dev/null +++ b/templates/express_auth/config/authConfig.js @@ -0,0 +1,15 @@ +export const authConfig = { + PORT: process.env.PORT || 8080, + DB: { + HOST: process.env.DB_HOST || "127.0.0.1", + PORT: process.env.DB_PORT || 27017, + NAME: process.env.DB_NAME || "auth_db", + }, + JWT: { + SECRET: process.env.JWT_SECRET || "default_secret", + EXPIRES_IN: process.env.JWT_EXPIRES_IN || "1d", + }, + router: { + AUTH_PREFIX: "/api/auth", + }, +}; diff --git a/templates/express_auth/connection/connection.js b/templates/express_auth/connection/connection.js new file mode 100644 index 00000000..e9f87a93 --- /dev/null +++ b/templates/express_auth/connection/connection.js @@ -0,0 +1,14 @@ +import mongoose from "mongoose"; +import { authConfig } from "../config/authConfig.js"; + +const databaseUrl = `mongodb://${authConfig.DB.HOST}:${authConfig.DB.PORT}/${authConfig.DB.NAME}`; + +export const connectDB = async () => { + try { + await mongoose.connect(databaseUrl); + console.log("MongoDB Connected Successfully."); + } catch (err) { + console.error(`MongoDB Connection Failed: ${err.message}`); + process.exit(1); + } +}; diff --git a/templates/express_auth/controller/authController.js b/templates/express_auth/controller/authController.js new file mode 100644 index 00000000..856fcba4 --- /dev/null +++ b/templates/express_auth/controller/authController.js @@ -0,0 +1,57 @@ +import jwt from "jsonwebtoken"; +import { User } from "../models/User.js"; +import { authConfig } from "../config/authConfig.js"; + +const generateToken = (id) => { + return jwt.sign({ id }, authConfig.JWT.SECRET, { + expiresIn: authConfig.JWT.EXPIRES_IN, + }); +}; + +export const registerUser = async (req, res) => { + const { name, email, password } = req.body; + + try { + const userExists = await User.findOne({ email }); + if (userExists) { + return res.status(400).json({ message: "User already exists" }); + } + + const user = await User.create({ name, email, password }); + + res.status(201).json({ + _id: user._id, + name: user.name, + email: user.email, + token: generateToken(user._id), + }); + } catch (error) { + res.status(500).json({ message: error.message }); + } +}; + + +export const loginUser = async (req, res) => { + const { email, password } = req.body; + + try { + const user = await User.findOne({ email }); + + if (user && (await user.comparePassword(password))) { + res.json({ + _id: user._id, + name: user.name, + email: user.email, + token: generateToken(user._id), + }); + } else { + res.status(401).json({ message: "Invalid email or password" }); + } + } catch (error) { + res.status(500).json({ message: error.message }); + } +}; + +export const getUserProfile = async (req, res) => { + res.json(req.user); +}; \ No newline at end of file diff --git a/templates/express_auth/index.js b/templates/express_auth/index.js new file mode 100644 index 00000000..837f3c60 --- /dev/null +++ b/templates/express_auth/index.js @@ -0,0 +1,36 @@ +import express from "express" +import cors from "cors" + +import { authConfig } from "./config/authConfig.js"; +import { authRouter } from "./router/authRouter.js"; + +import { initLog } from "./logs/initLog.js"; + +import { connectDB } from "./connection/connection.js"; + +const app = express(); + +initLog(); + +app.use(cors()); +app.use(express.json()); + +app.use(authConfig.router.AUTH_PREFIX, authRouter); + +app.get("/", (req, res) => { + res.json({ message: "auth server is running" }); +}); + +const startServer = async () => { + await connectDB(); + app.listen(authConfig.PORT, () => { + console.info( + `Server is running on http://127.0.0.1:${authConfig.PORT}`, + ); + console.warn( + `Test registration at http://127.0.0.1:${authConfig.PORT}${authConfig.router.AUTH_PREFIX}/register`, + ); + }); +}; + +startServer(); diff --git a/templates/express_auth/logs/initLog.js b/templates/express_auth/logs/initLog.js new file mode 100644 index 00000000..75bdbfa0 --- /dev/null +++ b/templates/express_auth/logs/initLog.js @@ -0,0 +1,7 @@ +import { existsSync, mkdirSync } from "fs"; + +export const initLog = () => { + if (!existsSync("./logs")) { + mkdirSync("./logs"); + } +}; diff --git a/templates/express_auth/middleware/authMiddleware.js b/templates/express_auth/middleware/authMiddleware.js new file mode 100644 index 00000000..ade3f685 --- /dev/null +++ b/templates/express_auth/middleware/authMiddleware.js @@ -0,0 +1,26 @@ +import jwt from "jsonwebtoken"; +import { authConfig } from "../config/authConfig.js"; +import { User } from "../models/User.js"; + +export const protect = async (req, res, next) => { + let token; + + if ( + req.headers.authorization && + req.headers.authorization.startsWith("Bearer") + ) { + try { + token = req.headers.authorization.split(" ")[1]; + const decoded = jwt.verify(token, authConfig.JWT.SECRET); + + req.user = await User.findById(decoded.id).select("-password"); + next(); + } catch (error) { + res.status(401).json({ message: "Not authorized, token failed" }); + } + } + + if (!token) { + res.status(401).json({ message: "Not authorized, no token" }); + } +}; diff --git a/templates/express_auth/models/User.js b/templates/express_auth/models/User.js new file mode 100644 index 00000000..51496168 --- /dev/null +++ b/templates/express_auth/models/User.js @@ -0,0 +1,36 @@ +import mongoose from "mongoose"; +import bcrypt from "bcryptjs"; + +const userSchema = new mongoose.Schema( + { + name: { + type: String, + required: true, + }, + email: { + type: String, + required: true, + unique: true, + lowercase: true, + }, + password: { + type: String, + required: true, + minlength: 6, + }, + }, + { timestamps: true }, +); + +userSchema.pre("save", async function (next) { + if (!this.isModified("password")) return next(); + this.password = await bcrypt.hash(this.password, 10); + next(); +}); + +userSchema.methods.comparePassword = async function (enteredPassword) { + return await bcrypt.compare(enteredPassword, this.password); +}; + +export const User = mongoose.model("User", userSchema); + diff --git a/templates/express_auth/package.json b/templates/express_auth/package.json new file mode 100644 index 00000000..daa35041 --- /dev/null +++ b/templates/express_auth/package.json @@ -0,0 +1,24 @@ +{ + "name": "express_auth", + "version": "1.0.0", + "description": "Express.js server with Custom JWT Authentication and MongoDB.", + "main": "index.js", + "scripts": { + "start": "node index.js", + "dev": "nodemon index.js" + }, + "author": "quick_start_express", + "license": "ISC", + "dependencies": { + "bcryptjs": "^2.4.3", + "cors": "^2.8.5", + "dotenv": "^16.4.7", + "express": "^4.21.1", + "jsonwebtoken": "^9.0.2", + "mongoose": "^8.9.3" + }, + "devDependencies": { + "nodemon": "^3.1.9" + }, + "type": "module" +} \ No newline at end of file diff --git a/templates/express_auth/router/authRouter.js b/templates/express_auth/router/authRouter.js new file mode 100644 index 00000000..f1570622 --- /dev/null +++ b/templates/express_auth/router/authRouter.js @@ -0,0 +1,16 @@ +import express from "express" +import { + registerUser, + loginUser, + getUserProfile, +} from "../controller/authController.js"; +import { protect } from "../middleware/authMiddleware.js"; + +const router=express.Router() + +router.post("/register", registerUser); +router.post("/login", loginUser); + +router.get("/profile", protect, getUserProfile); + +export { router as authRouter }; From 9dcef40bbafa671fafebea8521dea02eb83feb3a Mon Sep 17 00:00:00 2001 From: Priyansh Narang <145008344+priyansh-narang2308@users.noreply.github.com> Date: Wed, 7 Jan 2026 22:41:30 +0530 Subject: [PATCH 2/3] fix: resolve CI formatting issues and increase test timeouts --- .../express_auth/controller/authController.js | 3 +-- templates/express_auth/index.js | 4 ++-- templates/express_auth/models/User.js | 1 - templates/express_auth/package.json | 2 +- templates/express_auth/router/authRouter.js | 4 ++-- test/init.test.js | 16 ++++++++-------- 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/templates/express_auth/controller/authController.js b/templates/express_auth/controller/authController.js index 856fcba4..ca35b977 100644 --- a/templates/express_auth/controller/authController.js +++ b/templates/express_auth/controller/authController.js @@ -30,7 +30,6 @@ export const registerUser = async (req, res) => { } }; - export const loginUser = async (req, res) => { const { email, password } = req.body; @@ -54,4 +53,4 @@ export const loginUser = async (req, res) => { export const getUserProfile = async (req, res) => { res.json(req.user); -}; \ No newline at end of file +}; diff --git a/templates/express_auth/index.js b/templates/express_auth/index.js index 837f3c60..8ed7a2e4 100644 --- a/templates/express_auth/index.js +++ b/templates/express_auth/index.js @@ -1,5 +1,5 @@ -import express from "express" -import cors from "cors" +import express from "express"; +import cors from "cors"; import { authConfig } from "./config/authConfig.js"; import { authRouter } from "./router/authRouter.js"; diff --git a/templates/express_auth/models/User.js b/templates/express_auth/models/User.js index 51496168..804894c8 100644 --- a/templates/express_auth/models/User.js +++ b/templates/express_auth/models/User.js @@ -33,4 +33,3 @@ userSchema.methods.comparePassword = async function (enteredPassword) { }; export const User = mongoose.model("User", userSchema); - diff --git a/templates/express_auth/package.json b/templates/express_auth/package.json index daa35041..6200ab87 100644 --- a/templates/express_auth/package.json +++ b/templates/express_auth/package.json @@ -21,4 +21,4 @@ "nodemon": "^3.1.9" }, "type": "module" -} \ No newline at end of file +} diff --git a/templates/express_auth/router/authRouter.js b/templates/express_auth/router/authRouter.js index f1570622..22251de1 100644 --- a/templates/express_auth/router/authRouter.js +++ b/templates/express_auth/router/authRouter.js @@ -1,4 +1,4 @@ -import express from "express" +import express from "express"; import { registerUser, loginUser, @@ -6,7 +6,7 @@ import { } from "../controller/authController.js"; import { protect } from "../middleware/authMiddleware.js"; -const router=express.Router() +const router = express.Router(); router.post("/register", registerUser); router.post("/login", loginUser); diff --git a/test/init.test.js b/test/init.test.js index 4303f54a..6fe38bd7 100644 --- a/test/init.test.js +++ b/test/init.test.js @@ -154,7 +154,7 @@ describe("normal init with default settings", () => { expect(hasNodemon()).toBe(true); expect(nodeModulesExist()).toBe(true); - }, 25000); + }, 60000); }); }); @@ -185,7 +185,7 @@ describe("init --remove-deps", () => { expect(hasNodemon()).toBe(true); expect(nodeModulesExist()).toBe(false); - }, 25000); + }, 60000); }); }); @@ -249,7 +249,7 @@ describe("init with custom template name without installing deps", () => { }, ); verifyPackageName(validName); - }, 25000); + }, 60000); test("valid template name: lowercase only", async () => { const validName = "validname"; @@ -260,7 +260,7 @@ describe("init with custom template name without installing deps", () => { }, ); verifyPackageName(validName); - }, 25000); + }, 60000); test("valid template name: URL friendly characters", async () => { const validName = "valid-name"; @@ -271,7 +271,7 @@ describe("init with custom template name without installing deps", () => { }, ); verifyPackageName(validName); - }, 25000); + }, 60000); // TODO: Add test for cases where `inquirer` prompts are used for this. }); @@ -304,7 +304,7 @@ describe("init without nodemon option without installing deps.", () => { "nodemon", ); } - }, 25000); + }, 60000); }); }); @@ -335,7 +335,7 @@ describe("init with docker-compose without cache service and db", () => { expect(nodeModulesExist()).toBe(false); verifyDockerFiles(); - }, 25000); + }, 60000); }); }); @@ -388,6 +388,6 @@ describe("init with docker-compose with cache service and db", () => { expect(nodeModulesExist()).toBe(false); verifyDockerFiles(); - }, 25000); + }, 60000); }); }); From 27005b1be92ba91101765645171f4adcb2326a92 Mon Sep 17 00:00:00 2001 From: Priyansh Narang <145008344+priyansh-narang2308@users.noreply.github.com> Date: Wed, 7 Jan 2026 22:48:26 +0530 Subject: [PATCH 3/3] fix: update list test expectations for express_auth --- test/list.test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/list.test.js b/test/list.test.js index c00aa192..5415d459 100644 --- a/test/list.test.js +++ b/test/list.test.js @@ -26,7 +26,8 @@ Available Templates: - express_mysql - express_pg_prisma - express_oauth_microsoft -- express_oauth_google\n`; +- express_oauth_google +- express_auth\n`; describe("List Command", () => { test("list", async () => {