Cannot set headers to pass token in node js - node.js

node js
This is my register method to register a user. I am trying to pass token in headers when a user is registered which will be used in the front end to access the token and store it in the local storage.
module.exports.register = async function (req, res, next) {
try {
const { username, email, password } = req.body;
const profileImage = req.file.path;
const usernameCheck = await User.findOne({ username });
if (usernameCheck)
return res.json({ msg: "Username already used", status: false });
const emailCheck = await User.findOne({ email });
if (emailCheck)
return res.json({ msg: "Email already exists", status: false });
const hashedPassword = await bcrypt.hash(password, 10);
const user = await User.create({
_id: new mongoose.Types.ObjectId(),
username,
email,
profileImage,
password: hashedPassword,
});
delete user.password;
//create jwt token
const token = jwt.sign(
{
username: user.username,
email: user.email,
userId: user._id,
},
process.env.JWT_KEY,
{
expiresIn: "1h",
}
);
res.header("x-auth-token", token); //This is not setting the token in headers
return res.json({
message: "User Created Successfully",
status: true,
user,
});
} catch (ex) {
next(ex);
}
};
react js
This is my front-end react code to register a user. I want to login the user with the jwt token stored in localStorage once the user is registered.
const handleSubmit = async (values) => {
try {
const { username, email, profileImage, password } = values;
const formData = new FormData();
formData.append("username", username);
formData.append("email", email);
formData.append("profileImage", profileImage);
formData.append("password", password);
const response = await register(formData);
console.log(response);
if (response.status === false) return;
else {
loginWithJwt(response.headers["x-auth-token"]);// log the user in using jwt token
console.log(response.headers["x-auth-token"]);
navigate("/chatroom");
}
} catch (ex) {
console.log(ex.message);
}
};

Related

Express routing error Cannot Get / user/:id/verify/:token

I am trying to implement mail verification. Mail is receiveing fine but when clicking on the link getting an error like this "Cannot GET /user/6384a42492b85313e4186ce5/verify/2c561eee58759671236c3c275381f993c7b75939e167b7bdb11e5fa4d05cbf8f".
In controllers/userControllers.js the following code:
module.exports.signUp = async (req, res) => {
try {
const { error } = validate(req.body);
if (error) return res.status(400).send(error.details[0].message);
let user = {};
user = await User.findOne({
email: req.body.email,
});
if (user) return res.status(400).send("User already registered");
user = new User(_.pick(req.body, ["name", "email", "password"]));
const salt = await bcrypt.genSalt(10);
user.password = await bcrypt.hash(user.password, salt);
// user = await new User({ ...req.body, password: hashPassword }).save();
//const token = user.generateJWT();
const token = await new Token({
userId: user._id,
token: crypto.randomBytes(32).toString("hex"),
}).save();
const result = await user.save();
//save();
const url = `${process.env.BASE_URL}user/${user.id}/verify/${token.token}`;
await sendEmail(user.email, "Verify Email", url);
return res.status(201).send({
// message: "Registration Successfull!!",
message: "An Email sent to your account please verify",
token: token,
user: _.pick(result, ["_id", "name", "email"]),
});
} catch (error) {
console.log(error);
res.status(500).send({ message: "Internal Server Error" });
}
};
In router/userRouter.js page the following code:
const express = require("express");
const { User, validate } = require("../models/user");
const Token = require("../models/token");
const router = express.Router();
const {
signUp,
signIn,
verifyOTP,
resendOTP,
} = require("../controllers/userControllers");
const auth = require("../middlewares/authorize");
const admin = require("../middlewares/admin");
router.route("/signup").post(signUp);
router.get("/:id/verify/:token/", async (req, res) => {
try {
const { error } = validate(req.body);
if (error) return res.status(400).send(error.details[0].message);
const user = await User.findOne({ _id: req.params.id });
if (!user) return res.status(400).send({ message: "Invalid link" });
const token = await Token.findOne({
userId: user._id,
token: req.params.token,
});
if (!token) return res.status(400).send({ message: "Invalid link" });
await User.updateOne({ _id: user._id }, { verified: true });
await token.remove();
res.status(200).send({ message: "Email verified successfully" });
} catch (error) {
res.status(500).send({ message: "Internal Server Error" });
}
});
router.route("/signin").post(signIn);
module.exports = router;
Any Ideas ?
Thanks.
After clicking the url in mail it should go the the login page.

Mongoose return "new ObjectId("//id")" instead of just the id

I am trying to do my login function (I am using bcrypt and jsonwebtoken) the problem is that console.log (user._id) returns me "new ObjectId (" 6148f043ebbaa0ab41ac8499 ")" instead of just "6148f043ebbaa0ab41ac8499" , which would be easier for the creation of the token.
module.exports.login = async (req, res) => {
const { email, password } = req.body;
// Compare the req.body.password to the hashed password in DB
const user = await UserModel.findOne({ email: email });
const match = await bcrypt.compare(password, user.password);
if (match) {
try {
const user = await UserModel.findOne({ email: email });
console.log(user._id);
// Assign a token
const token = jwt.sign({ userId: user._id }, process.env.LOGIN_TOKEN, {
expiresIn: "1h",
});
console.log(token);
res.cookie("jwt", token, { httpOnly: true});
res.status(200).json({ user: user._id });
} catch (err) {
res.status(500).json(err);
}
} else {
res.status(500).json({ message: "error!!!" });
}
};
How to fix this please?
That is a normal behaviour. Since you got an ObjectId, you can convert it to a string by calling the toHexString() method on it. I have also modified the code to check for an undefined user, and removed the extra call to find a user since you already did in the previous line. Please see updated code:
module.exports.login = async (req, res) => {
const { email, password } = req.body;
const user = await UserModel.findOne({ email: email });
if (!user) {
return res.status(400).json({ message: "Unauthorised"});
}
// Compare the req.body.password to the hashed password in DB
const match = await bcrypt.compare(password, user.password);
if (match) {
try {
// Convert user id (ObjectId) to a string
const userId = user._id.toHexString();
// Now user id is a string
console.log(userId);
// Assign a token
const token = jwt.sign({ userId }, process.env.LOGIN_TOKEN, {
expiresIn: "1h",
});
console.log(token);
res.cookie("jwt", token, { httpOnly: true});
res.status(200).json({ user });
} catch (err) {
res.status(500).json(err);
}
} else {
res.status(400).json({ message: "Unauthorised" });
}
};
use the following
const id = _id.toHexString();

How to add a new key and value to existing document in MongoDB

I want to add the refreshtoken to the user info when the user logs in. So I can get the refreshtoken and pass it in my cookies.
Code:
router.post("/login", async (req, res) => {
const user = await User.findOne({ email: req.body.email });
if (!user) res.status(400).send({ msg: "User does not exists" });
const validPass = await compare(req.body.password, user.password);
if (!validPass) {
return res.status(400).json({ msg: "email or password is incorrect" });
}
const accesstoken = createAccessToken(user._id);
const refreshtoken = createRefreshToken(user._id);
//create different versions of the refresh token
// put the refreshtoken in the database
User.update(
{ id: user._id },
{
$set: {
refreshtoken: refreshtoken,
},
},
);
let userToken = user.refreshtoken;
userToken = refreshtoken;
//send token. Refreshtoken as a cookie and accesstoken as a regular
//response
//YOU HAVE ALREADY SAID IN THE SENDACCESTOKEN FUNCTION THAT YOU WOULD SEND THE MAIL ALSO
sendRefreshToken(res, refreshtoken);
sendAccessToken(req, res, user._id, accesstoken);
});

Update a property in document in an Express route (Mongoose, MongoDB, Express)

I've successfully set up the registration and login functionality using Express, MongoDB and Mongoose.
I would like to log when the user last visited the site once the user's credential is accepted in a lastConnection property of the user document,
I tried but "lastConnection" is null (see the line below where I add a comment)
router.post("/login", async function(req, res) {
const { errors, isValid } = validateLoginInput(req.body);
if (!isValid) {
return res.status(400).json(errors);
}
const email = req.body.email;
const password = req.body.password;
const user = await User.findOne({ email }).then(user => {
if (!user) {
errors.email = "Email already exists";
}
console.log("user ", user); <-- returns an object with the datas of user
bcrypt.compare(password, user.password).then(isMatch => {
if (isMatch) {
const payload = {
id: user.id,
name: user.name
};
user.lastConnection = new Date(); <-- doesn't work
jwt.sign(
payload,
keys.secretOrKey,
{
expiresIn: 7200
},
(err, token) => {
res.json({
success: true,
token: "Bearer " + token
});
}
);
} else {
errors.password = "Password is not correct";
// return res
// .status(400)
// .json({ passwordincorrect: "Password incorrect" });
}
});
});
return {
errors,
isValid: isEmpty(errors)
};
});
Any ideas? I think I have to do an update but I don't know where to put it
Try replacing user.lastConnection = new Date(); with
user.update({ lastConnection: new Date() })
.then( updatedUser => {
console.log(updatedUser)
// put jwt.sign code here
})

How to expose the x-token from server side in express

I have the following auth route in the backend of my API:
router.post('/', async (req, res) => {
const { error } = validate(req.body);
if (error) return res.status(400).send(error.details[0].message);
let user = await User.findOne({ username: req.body.username });
if (!user) return res.status(400).send('Invalid username or password.');
const validPassword = await bcrypt.compare(req.body.password, user.password);
if (!validPassword) return res.status(400).send('Invalid username or password.');
const token = user.generateAuthToken();
res.header('Access-Control-Expose-Headers', 'X-OBSERVATORY-AUTH');
res.header('X-OBSERVATORY-AUTH', token).send(_.pick(user, ['_id', 'email', 'username','isAdmin']));
});
And in the frontend i have the following handler for the login:
login( username: string, password: string) {
var user: User = { username: username, password: password };
this.http
.post<any>("http://localhost:3000/api/auth",user, {observe:'response'})
.subscribe((res) => {
const token = res.headers.get('X-OBSERVATORY-AUTH');
this.token = token;
console.log(res.headers.get('X-OBSERVATORY-AUTH'));
if (token!==null) {
this.isAuthenticated = true;
this.userId = res.body._id;
this.isAdmin=res.body.isAdmin;
this.authStatusListener.next(true);
this.saveAuthData(token, this.userId, this.isAdmin);
}
});
}
What I am trying to do is to pass the X-OBSERVATORY-AUTH in the response header but I cant figure how to expose the token from the backend. What should I do?

Resources