JWT-bcrypt-learning

This commit is contained in:
jaanvi 2025-06-03 11:51:54 +05:30
parent d23fa693ea
commit e1a60bdccd
11 changed files with 306 additions and 37 deletions

27
app.js
View file

@ -2,34 +2,23 @@ require("dotenv").config();
const express = require("express");
const connectDB= require("./config/db");
const userRoutes= require("./routes/userRoutes");
const authRoutes = require("./routes/authRoutes");
const logger = require('./middleware/logger')
const app= express();
const PORT = process.env.PORT || 5000;
//DB connection:Done
connectDB();
//use in built-middleware to parse the data form body
app.use(express.urlencoded({ extended: false }))
//parse the json data
app.use(express.json());
//parse the url-encoded data
app.use(express.urlencoded({ extended: false }));
app.use(logger);
//Routes
app.use("/api/users",userRoutes);
app.use("/api/user", authRoutes);
app.listen(PORT,()=>{
console.log(`Server is running on port ${PORT}`);
})
// const logger = require("./middleware/logger");
// const userRoutes = require("./routes/userRoutes");
// const app = express();
// const PORT = process.env.PORT || 5000;
// connectDB();
// app.use(express.json());
// app.use(logger); // custom middleware
// app.use("/api/users", userRoutes);
// app.listen(PORT, () => {
// console.log(`Server is running on port ${PORT}`);
// });

View file

@ -1,4 +1,5 @@
const mongoose = require("mongoose");
const connectDB = async()=>{
try{
await mongoose.connect(process.env.MONGO_URI);
@ -10,3 +11,6 @@ const connectDB = async()=>{
}
module.exports = connectDB;

View file

@ -0,0 +1,58 @@
const User = require("../models/User");
const jwt = require("jsonwebtoken");
const generateToken = (id) => {
return jwt.sign({ id }, process.env.JWT_SECRET, { expiresIn: "1h" });
};
//Register
const registerUser = async (req, res) => {
const { username, 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({ username, email, password });
res.status(201).json({
_id: user._id,
username: user.username,
email: user.email,
token: generateToken(user._id),
});
} catch (error) {
console.error("Error in registerUser:", error.message);
res.status(500).json({ message: "Server error" });
}
};
//Login
const loginUser = async (req, res) => {
const { email, password } = req.body;
try {
const user = await User.findOne({ email });
if (!user) return res.status(400).json({ message: "Invalid credentials" });
const isMatch = await user.matchPassword(password);
if (!isMatch)
return res.status(400).json({ message: "Invalid credentials" });
res.status(200).json({
_id: user._id,
username: user.username,
email: user.email,
token: generateToken(user._id),
message: "success",
});
} catch (error) {
res.status(500).json({ message: "Server error" });
}
};
const getProfile = async (req, res) => {
res.json(req.user);
};
module.exports = { registerUser, loginUser, getProfile };

View file

@ -52,6 +52,7 @@ const deleteUser= async(req,res)=>{
if(!user){
return res.status(404).json({message: "User not found"});
}
res.status(200).json({message:"success"})
} catch (err) {
res.status(500).json({ error: err.message });
}

View file

@ -0,0 +1,24 @@
const jwt = require("jsonwebtoken");
const User = require("../models/User");
const authToken = async (req, res, next) => {
let token;
if (
req.headers.authorization &&
req.headers.authorization.startsWith("Bearer")
) {
try {
token = req.headers.authorization.split(" ")[1]; // Correct split by space
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = await User.findById(decoded.id).select("-password");
next();
} catch (error) {
console.error(error);
res.status(401).json({ message: "Not authorized, token failed" });
}
} else {
res.status(401).json({ message: "Not authorized, no token" });
}
};
module.exports = authToken;

6
middleware/logger.js Normal file
View file

@ -0,0 +1,6 @@
// logger.js
function logger(req, res, next) {
console.log(`${req.method} ${req.url} at ${new Date().toISOString()}`);
next();
}
module.exports = logger;

View file

@ -1,8 +1,9 @@
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const userSchema = new mongoose.Schema({
first_name: {
type: String,
required:true
required: false,
},
last_name: {
type: String,
@ -10,10 +11,31 @@ const userSchema = new mongoose.Schema({
email: {
type: String,
required: true,
unique:true
unique: true,
},
age: {
type:Number
}
})
type: Number,
},
username: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
});
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) return next();
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
next();
});
userSchema.methods.matchPassword = async function (enteredPassword) {
return await bcrypt.compare(enteredPassword, this.password);
};
module.exports = mongoose.model("User", userSchema);

4
nodemon.json Normal file
View file

@ -0,0 +1,4 @@
{
"watch": ["."],
"legacyWatch": true
}

136
package-lock.json generated
View file

@ -9,8 +9,10 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"bcrypt": "^6.0.0",
"dotenv": "^16.5.0",
"express": "^5.1.0",
"jsonwebtoken": "^9.0.2",
"mongodb": "^6.16.0",
"mongoose": "^8.15.1",
"nodemon": "^3.1.10"
@ -72,6 +74,20 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/bcrypt": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-6.0.0.tgz",
"integrity": "sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"node-addon-api": "^8.3.0",
"node-gyp-build": "^4.8.4"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@ -135,6 +151,12 @@
"node": ">=16.20.1"
}
},
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
"license": "BSD-3-Clause"
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -293,6 +315,15 @@
"node": ">= 0.4"
}
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -655,6 +686,49 @@
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT"
},
"node_modules/jsonwebtoken": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
"license": "MIT",
"dependencies": {
"jws": "^3.2.2",
"lodash.includes": "^4.3.0",
"lodash.isboolean": "^3.0.3",
"lodash.isinteger": "^4.0.4",
"lodash.isnumber": "^3.0.3",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.once": "^4.0.0",
"ms": "^2.1.1",
"semver": "^7.5.4"
},
"engines": {
"node": ">=12",
"npm": ">=6"
}
},
"node_modules/jwa": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
"integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
"license": "MIT",
"dependencies": {
"buffer-equal-constant-time": "^1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jws": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
"license": "MIT",
"dependencies": {
"jwa": "^1.4.1",
"safe-buffer": "^5.0.1"
}
},
"node_modules/kareem": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
@ -664,6 +738,48 @@
"node": ">=12.0.0"
}
},
"node_modules/lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
"license": "MIT"
},
"node_modules/lodash.isboolean": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
"license": "MIT"
},
"node_modules/lodash.isinteger": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
"license": "MIT"
},
"node_modules/lodash.isnumber": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
"license": "MIT"
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"license": "MIT"
},
"node_modules/lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
"license": "MIT"
},
"node_modules/lodash.once": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"license": "MIT"
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -845,6 +961,26 @@
"node": ">= 0.6"
}
},
"node_modules/node-addon-api": {
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz",
"integrity": "sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==",
"license": "MIT",
"engines": {
"node": "^18 || ^20 || >= 21"
}
},
"node_modules/node-gyp-build": {
"version": "4.8.4",
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
"integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
"license": "MIT",
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
"node-gyp-build-test": "build-test.js"
}
},
"node_modules/nodemon": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",

View file

@ -11,10 +11,14 @@
"license": "ISC",
"description": "",
"dependencies": {
"bcrypt": "^6.0.0",
"dotenv": "^16.5.0",
"express": "^5.1.0",
"jsonwebtoken": "^9.0.2",
"mongodb": "^6.16.0",
"mongoose": "^8.15.1",
"nodemon": "^3.1.10"
}
}

21
routes/authRoutes.js Normal file
View file

@ -0,0 +1,21 @@
const express = require("express");
const {
registerUser,
loginUser,
getProfile,
} = require("../controllers/authController");
const authToken = require("../middleware/authMiddleware");
const router = express.Router();
// Register user
router.post("/register",registerUser );
// Login user
router.post("/login", loginUser);
//protectRoute
router.get("/profile", authToken, getProfile);
module.exports = router;