I am making a login system in mern stack, i am using jwt token based login system in the backend. In the provided code i am querying database for every page user requests to check wheather user is present in database. I don’t want to run database query for every request how can i make this better and save user information in token and authenticate user with token. Will this be a good idea?, i am a beginner.
// Login Controller
const loginUser = asyncHandler(async (req, res) => {
const { email, password } = req.body;
// Validation
if (!email || !password) {
res.status(400);
throw new Error("Email and Password is Required");
}
// check if user exist
const user = await userModel.findOne({ email });
if (!user) {
res.status(400);
throw new Error("User does not Exist. Please Signup");
}
// check if password matches
const isPasswordMatch = await bcrypt.compare(password, user.password);
if (!isPasswordMatch) {
res.status(400);
throw new Error("Invalid Email or Password");
}
// Trigger 2FA for Unknown userAgent
const ua = parser(req.headers["user-agent"]);
const thisUserAgent = ua.ua;
console.log(thisUserAgent);
const allowedAgent = user.userAgent.includes(thisUserAgent);
if(!allowedAgent){
// generate 6 digit code
const loginCode = Math.floor(Math.random() * (999999 - 100000 + 1)) + 100000;
console.log(loginCode);
// encrypt login code before saving into db
const encryptedLoginCode = cryptr.encrypt(loginCode.toString());
// delete token if it exist in db
const userToken = await tokenModel.findOne({ userID: user._id});
if(userToken){
await userToken.deleteOne();
}
// save token to db
await new tokenModel({
userID: user._id,
loginToken: encryptedLoginCode,
createdAt: Date.now(),
expiresAt: Date.now() + 60 * ( 60 * 1000 ),
}).save();
res.status(400);
throw new Error("New browser or device detected");
}
// Generate Token
const token = generateToken(user._id);
if (user && isPasswordMatch) {
// Send HTTP-Only Cookie
res.cookie("token", token, {
httpOnly: true,
expires: new Date(Date.now() + 1000 * 86400), // 1 day
sameSite: "none",
secure: true,
});
// sending user data after login
const { _id, name, email, phone, bio, image, role, isVerified } = user;
res
.status(200)
.json({ _id, name, email, phone, bio, image, role, isVerified, token }); // attaching token into request
}
else{
res.status(500);
throw new Error("Something went wrong Please try again")
}
});
// Auth Middleware
const auth = asyncHandler(async (req, res, next) =>{
try {
const token = req.cookies.token;
// check if token is empty
if(!token){
res.status(401);
throw new Error("No Token Found, Please Login");
}
// Verify Token
const verified = jwt.verify(token, process.env.JWT_SECRET); // we can now get the user data associated with this token
// Get user id from token
const user = await userModel.findById(verified.id).select("-password"); // omiting password from sending to client
// check if uset not found
if(!user){
res.status(404);
throw new Error("User Not Found")
}
// if user is suspended
if(user.role === "suspended"){
res.status(400);
throw new Error("User Suspended please contact support");
}
// if everything is fine
req.user = user;
next();
} catch (error) {
// when a user is not authorized
console.log(error);
res.status(401);
throw new Error("Not Authorized. Please Login")
}
});
// Logout Controller
const logoutUser = asyncHandler(async (req, res)=>{
res.cookie("token", "", {
httpOnly: true,
expires: new Date(0), // expires immediately
sameSite: "none",
secure: true,
});
return res.json({ msg: "Logged Out"})
})
New contributor
Mujeeb is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.