Express GET request not working after adding authentication - node.js

I'm stuck on this very simple problem and I don't know what I am doing wrong. I'm creating a simple RESTAPI with users and authentication. This is the GET request that I'm trying to run:
router.get('/users/me',auth ,async(req,res)=>{
console.log(req.user)
console.log('Entered the get request')
res.send(getUserData(req.user)) })
Basically, at the end of the authentication, I save the user fetched from the database into req.user object and then I send it to the client using res.send(req.user). As you can see in the code below:
const auth = async(req,res,next)=>{
try{
const token = req.header('Authorization').replace('Bearer ','')
const decoded = jwt.verify(token,'secretkey')
const db = req.app.locals.database
const user = await db.collection('users').findOne({
_id: decoded.id,
'tokens.token':token
})
console.log(user)
if(!user){
throw new Error()
}
req.user = user
next()
}catch(e){
res.status(401).send('Please Authenticate')
}}
The problem is that this authentication function is working perfectly fine. I have used it on other routes as well. But in this GET request, the authentication function runs (I identified this using many console logs) and fetches the data correctly. But it doesn't enter the get request once the middleware(auth function) has completed the call.
From POSTMAN, when I send GET requests, I get a 404 error and I have no idea why. I have literally spent hours trying to make sense of this. Please help me out if you know what might be the problem.
EDIT: So I was able to run the get request by moving the request above the following request that I also have in the same file:
router.get('/users/:id',auth ,async(req,res)=>{
const id = req.params.id
const db = req.app.locals.database
try{
const result = await db.collection('users').findOne({_id: id})
const userData = getUserData(result)
res.status(200).send(userData)
}catch(e){
res.status(404).send()
}
})
But now this request doesn't work. I cant figure out what positioning has to do with requests functionality. Can anyone please explain?

Related

I'm trying to use node to login. I am using mongodb as my database, I am getting SyntaxError: Unexpected token '.' in "_id:findUser?._id,"

This is the code snippet. Node version v12.22.9
This error also popped up somewhere else, but i commented it because it was not that big a deal.
Essentially, this error is appearing everywhere I have used this format firstname:findUser?.firstname,. How do I deal with it?
//login fucntion
const loginUserCtrl = asyncHandler(async(req,res)=>{
//get email and pass
const {email,password} = req.body;
//console.log(email,password);
//check if user exists
const findUser = await User.findOne({email}); //true or false
if (findUser && await findUser.isPasswordMatched(password)){
//res.json(findUser); //return the found user
res.json({
_id:findUser?._id,
firstname:findUser?.firstname,
lastname:findUser?.lastname,
email:findUser?.email,
mobile:findUser?.mobile,
token:generateToken(findUser?._id),
});
}else{
res.send("Invalid credentials");
}
});
If the provided email and password match with credentials in the database, the system will generate a token and return the user data in form of a json
Edited:
I tried removing the ? in each of the lines and the code worked.

when building a fullstack project with express, how do I use "res.status(200).json( {some information...} )" in the front end?

I am learning about express servers, but I do not understand why all the tutorials I am watching are writing code like the following 3 lines when dealing with responses
res.status(200).json({user});
res.status(401).json("Wrong username");
res.status(500).json(err);
How does this help my home.html (or home.ejs) file??
for example, if I am building a login feature like:
router.post("/login", async (req, res) => {
try {
const user = await User.findOne({ username: req.body.username });
if (!user) {
return res.status(401).json("Wrong credentials!");
}
const hashedPassword = CryptoJS.AES.decrypt(user.password, process.env.PASS_SEC);
const originalPassword = hashedPassword.toString(CryptoJS.enc.Utf8);
if (req.body.password !== originalPassword) {
return res.status(401).json("Wrong credientials!");
}
const accessToken = jwt.sign(
{id: user._id, isAdmin: user.isAdmin},
process.env.JWT_SEC,
{expiresIn: "3d"}
);
const { password, ...others } = user._doc;
res.status(200).json({...others, accessToken});
} catch (err) {
res.status(500).json(err);
}
});
How does those "res.status" lines actually let me do things on the front end. Like how do I access this information, e.g. to save the accessToken in a request header for my next request, or how do I manipulate the html file to say hi ${user.username} or something like that.
Or if an error occures, how do I make my application say "username is wrong" or "login failed" or whatever, because res.status() is NOT doing any of that let me tell you...
99% of the content I find online uses react or angular, I only use plain JS and HTML, any help is appricated because I have no clue where to look and I have enough with learing express and do not want to learn react
In an express server you can return responses in an intuitive way like below:
return res.status(200).send({
'message' : 'Okay'
});
The status codes explain the status of the request. Though we have freedom to use any status code that we want the general practice is that the we follow:
2xx - Okay (request successful)
4xx - An issue with the client end of the request - you can use this to throw out errors when something is wrong with the client whos sending the request , like the user credentials is wrong or the requested record does not exists etc.
5xx - An issue with the server like the db connection failed, or file write failed etc.
On the front end depending on the status code of the request you can change the UI. Also note that the message that you send via res.send({}) is also available in the front end which u can use to show the user of the front end.

Sending data from react to node by get request using axios library

for more than 3 hours I'm handling with an issue, what I'm trying to do is sending a get request from react to nodejs using axios library, I wanna pass some data into this request, as we know the get request don't have a body, so I've sent the data as query parameter like that
// base URL
const url = "http://localhost:8080/loginAsTeacher";
if(loginAs === "loginTeacher"){
axios.get(url,{
params :{
email: "abc123#gmail.com",
password: "abc1234*"
}
})
.then(res => console.log(res)) // this line return status:200 and data:null
.catch(err => console.log(err.message))
}
so this request success but the problem is the email and password are not passing to the backend
router.get("/loginAsTeacher", async (req,res)=>{
// values coming from the client
const loginEmail = req.params.email;
const loginPassword = req.params.password;
console.log(req.params); // this line return {} empty object
// get data of that user by his/her mail
const teacherData = await myModel.findOne({
email: loginEmail
}).exec()
res.status(200).json({
status: 200,
data: teacherData
})
})
the console.log above return an empty object, which means there's no parameters
Is this not the right solution ???
thanks for reading
To get your queries you need to get req.query instead of req.params
Btw. it's dangerous to send sensitive data over get. It could be get logged in plaintext even over https
use req.query instead of req.params. it will solve the issue

Firebase on Express - Can't return response to client with .catch(error)

I've searched for hours and could not find a single relevant thing about this.
I am using firebase on my express web server for user (admin) authentification. I basically have a separate control panel for the admins separate from the mobile app so we can control the data from the users.
I currently have this post address that does the following:
app.post('/createNewAdminAccount', function(req, res){
const password = bcryptPassword(bcryptDetails, req.body.password);
const username = req.body.username;
const auth = firebase.auth();
let userExists = false;
function userExistsResponse(){
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ "userExists": true }));
}
const promise = auth.createUserWithEmailAndPassword(username, String(password));
promise.catch(function(error){
console.log(error.message);
userExistsResponse();
});
});
The way I have userExistsResponse(); isn't exactly how I have it, but for the sake of clarity, it's like that.
It seems that the .catch() function can only accept console.log(). I even looked at this which suggests stacking a .then(), error(error) but that doesn't work no matter how I write it, and using catch(error) doesn't seem to work either.
The goal is to see that the user is authenticated and respond to the client with a message as such. I've tried setting a variable to true (as you can see by the leftover let userExists = false variable), calling a function, doing a .then() statement without a .catch() (causes the server to break with an error), etc. None of it works, and after looking through YouTube videos, Firebase documentation, and StackOverflow, I have not found a useful answer.
FIXED Credit: 0x17
app.post('/createNewAdminAccount', authenticated, function(req, res){
const password = String(bcryptPassword(bcryptDetails, req.body.password));
const username = req.body.username;
admin.auth().getUserByEmail(username)
.then(function(userRecord) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ 'userExists': true }));
console.log('User Exists');
})
.catch(function(error) {
const promise = auth.createUserWithEmailAndPassword(username, password);
promise.catch(function(error){
console.log(error.message);
});
console.log('User Created');
});
});
From the way i see it, for the createNewAdminAccount route, Why not you do a check for the user in the first place using admin.auth().getUserByEmail(); analyse it's response code auth/email-already-exists or a combination of some listed in this link and then proceed with admin.auth().createUser() ?
Also if your goal is to just authenticate the user, should you not be using the below mentioned method and analyze the error code for the same ?
firebase.auth().signInWithEmailAndPassword(email, password).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});

ExpressJS app login fails after saving first login history

I've implemented a ExpressJS app using PassportJS, MongoDB (Mongoose) and JSON web tokens.
Inside successful login route implementation
await user.insertLoginTime();
const token = user.generateJwt();
res.status(200).json({ token });
Mongoose model method 'insertLoginTime'
userSchema.methods.insertLoginTime = async function() {
try {
const presentTime = new Date().getTime();
await this.loginHistory.push(presentTime);
await this.save();
return;
} catch (error) {
throw new Error(error);
}
};
First login is successful and 'Postman' receives token but returns invalid password error over next attempts.
Removing the 'insertLoginTime' method successfully logs-in on multiple attempts. Is there any mistake in the 'insertLoginTime' implementation?
I've resolved this issue. It was occurring because I added password hashing to Schema 'pre' hook for 'save'. On saving login history, the hashed password was being hashed again and saved back. This was deleting the actual password hash and causing next attempts to fail.

Resources