Password Reset Auth using MERN Stack - node.js

I'm implementing an auth token within the nodemailer email that is sent whenever a user resets their password. I've got the generated url with the appended token setup and sending properly, I just can't seem to get my routing right to handle the authentication of said token.
My request is returning a 404 saying my GET is not found (GET http://localhost:3000/reset/XXXXXXXXXXXX 404 (Not Found) ). Could anyone help point me in the right direction here?
Here's my api route for the server
router.get('/reset', (req, res, next) => {
User.findOne({ resetPasswordToken: req.query.resetPasswordToken }).then(user => {
if (user == null) {
res.json('Password link is invalid or has expired');
} else {
res.status(200).send({
username: user.email,
message: 'Password link accepted',
})
}
})
});
And my code to handle the request
componentDidMount() {
console.log(this.props.match.params.token);
axios.get('/reset' + this.props.match.params.token)
.then(response => {
// Conditional logic here based on response returned
})
.catch(function (error) {
console.log(error);
})
}

You need to tell express to expect the parameter in the url like this:
router.get('/reset/:token', (req, res, next) => {
// token is inside req.params.token
User.findOne({ resetPasswordToken: req.params.token }).then(user => {
if (user == null) {
res.json('Password link is invalid or has expired');
} else {
res.status(200).send({
username: user.email,
message: 'Password link accepted',
})
}
})
});
Then make sure there is a slash in the url when you make the request:
axios.get('/reset/' + this.props.match.params.token)
.then(response => {
// Conditional logic here based on response returned
})
.catch(function (error) {
console.log(error);
})

Related

forgotten password with node and sendgride issue

I have tried to set up the forgot password backend as follows but it seems not to work.
exports.forgotPassword = (req, res) => {
const { email } = req.body.email;
User.findOne({ email }, (err, user) => {
if (err || !user) {
return res.status(401).json({
error: 'User with that email does not exist'
});
}
const token = jwt.sign({ _id: user._id }, process.env.JWT_RESET_PASSWORD, { expiresIn: '10m' });
// email
const emailData = {
from: process.env.EMAIL_FROM,
to: email,
subject: `Password reset link`,
html: `
<p>Please use the following link to reset your password:</p>
<p>${process.env.CLIENT_URL}/auth/password/reset/${token}</p>
<hr />
<p>This email may contain sensetive information</p>
`
};
// populating the db > user > resetPasswordLink
return user.updateOne({ resetPasswordLink: token }, (err, success) => {
if (err) {
return res.json({ error: errorHandler(err) });
} else {
sgMail.send(emailData).then(sent => {
return res.json({
message: `Email has been sent to ${email}. Follow the instructions to reset your password. Link expires in 10min.`
});
});
}
});
});
};
Test on postman showing sending without success and error
up on canceling the continues sending a request in postman, there is no error in postman console. However, my terminal console has this funny response
I will appreciate any help.
Thank you.
Since express doesn't know when to go from a function to another function, you need to call the next() argument, passed to these functions (in this case: forgotPasswordValidator and forgotPassword). You can find more on that here: http://expressjs.com/en/guide/using-middleware.html
The router:
const validationRules = () => {
return [
check('email')
.notEmpty().withMessage('Please add an email address')
.isEmail().withMessage('Must be a valid email address')
]
}
router.put("/forgot-password", validationRules(), forgotPasswordValidator, forgotPassword);
forgotPasswordValidator middleware function:
const { validationResult } = require('express-validator');
exports.forgotPasswordValidator = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
} else next()
};
The forgotPassword function seems fine, but if you have any more problems feel free to write a comment.

Refreshing JWT access token with refresh token within single middleware function on a post route

I'm trying to learn JWT authentication in express and one thing that I'm came across this code from Github
that this guy has initialised an middleware function to authenticate and check expiry of access token as per below:
app.post("/protected", auth, (req, res) => {
return res.json({ message: "Protected content!" });
})
async function auth(req, res, next) {
let token = req.headers["authorization"];
token = token.split(" ")[1]; //Access token
jwt.verify(token, "access", async (err, user) => {
if (user) {
req.user = user;
next();
} else if (err.message === "jwt expired") {
return res.json({
success: false,
message: "Access token expired"
});
} else {
console.log(err);
return res
.status(403)
.json({ err, message: "User not authenticated" });
}
});
}
and a separate route for refreshing the access token with the help of refresh token
app.post("/refresh", (req, res, next) => {
const refreshToken = req.body.token;
if (!refreshToken || !refreshTokens.includes(refreshToken)) {
return res.json({ message: "Refresh token not found, login again" });
}
// If the refresh token is valid, create a new accessToken and return it.
jwt.verify(refreshToken, "refresh", (err, user) => {
if (!err) {
const accessToken = jwt.sign({ username: user.name }, "access", {
expiresIn: "20s"
});
return res.json({ success: true, accessToken });
} else {
return res.json({
success: false,
message: "Invalid refresh token"
});
}
});
});
So, my question is how secure it is and how can I create single middleware function that could do both authentication and refreshing access token without hitting the app.post('/refresh') as in my view it wouldn't be a smooth experience to deal with it in frontend API management within react
Edit
My middleware seems to work well but it doesn't identify the wrong refresh token and then actually getting worked on protected route
app.post('/home', authenticateUser, (req, res) => {
res.send('welcome');
});
async function authenticateUser(req, res, next) {
let token = req.headers['authorization'];
token = token.split(' ')[1];
jwt.verify(token, JWT_AUTH_TOKEN, async (err, phone) => {
if (phone) {
req.phone = phone;
next();
} else if (err) {
const refreshToken = req.body.refreshToken;
if (!refreshToken || !refreshTokens.includes(refreshToken)) {
return res.json({ message: 'Refresh token not found, login again' });
} else {
jwt.verify(refreshToken, JWT_REFRESH_TOKEN, (err, phone) => {
if (!err) {
const accessToken = jwt.sign({ phone }, JWT_AUTH_TOKEN, { expiresIn: '30s' });
return res.json({ success: true, accessToken });
} else {
return res.json({
success: false,
message: 'Invalid refresh token'
});
}
next();
});
}
} else {
console.log(err);
return res.status(403).json({ err, message: 'User not authenticated' });
}
});
}

why is my jwt token returning null on the backside but not the front

I am trying to make a GET request to my mLab database. I pass a JWT token with the request and logged it on both the client and server. It reads correctly on the client but shows null on the server. Any help would be much appreciated. I am using Node.js and Angular.
I am pretty new to this, so I apologize in advance if the mistake is obvious.
Here is the server's GET route:
router.get('/', (req, res, next) => {
var decoded = jwt.decode(req.query.token);
console.log(decoded);
console.log('employees');
if(decoded) {
return Company.find({_id: decoded._id})
.populate('user', 'firstName')
.exec(function(err, company) {
if (err) {
return res.status(500).json({
title: 'An error occurred',
error: err
});
}
res.status(200).json({
message: 'Success',
obj: company
});
});
} else {
return res.status(401).json({
title: 'Not authenticated',
error: {
message: 'Please create an account or sign in'
}
});
}
console.log(company);
});
Here is the client:
getEmployees() {
const token = localStorage.getItem('token')
? '?token=' + localStorage.getItem('token')
: '';
console.log(token);
return this.http.get('http://localhost:3000/company' + token)
.map((response: Response) => {
const employees = response.json().obj;
console.log(employees);
let transformedEmployees: Employee[] = [];
for (let employee of employees) {
transformedEmployees.push(new Employee(
employee.firstName,
employee.lastName,
employee.email,
employee.password,
employee.jobTitle,
employee.isAdmin,
employee.tasks
));
}
console.log(transformedEmployees)
this.employees = transformedEmployees;
return transformedEmployees;
})
.catch((error: Response) => {
this.errorService.handleError(error.json());
return Observable.throw(error.json())
});
}
You should NOT be placing your token in the Authorization header of your request.
You use an express middleware to decode the token:
const myDecoder = (req, res, next) => {
req.user = jwt.decode(req.headers.authorization);
next();
}
Then, you place in your route:
router.get('/', myDecoder, (req, res) => {
let user = req.user;
console.log(user);
console.log('employees');
if (user) { blah }
...
Should not be passing the entire token over the URL itself.

checking Jwt token on every request?

I am developing a android aplication with nodejs and postgreSQL, at the moment i just have the login and the register.
When i do a login and everything is fine the server send me a token, that token is stored on the device SharedPreference, now my confusion is, do i need to decode this token on every request, or do i need to do it just 1 time?
in this tutorial at the end, he decodes on every route the token, but i don't need to do that when i do for example a request to register.
What is the best way to implement this?
here is my server code:
//****************************************************Begin of login request **********************************/
router.post('/login', function (req, res, next) {
if (JSON.stringify(req.body) == "{}") {
return res.status(400).json({ Error: "Login request body is empty" });
}
if (!req.body.username || !req.body.password) {
return res.status(400).json({ Error: "Missing fields for login" });
}
// search a user to login
User.findOne({ where: { username: req.body.username } }) // searching a user with the same username and password sended in req.body
.then(function (user) {
if (user && user.validPassword(req.body.password)) {
//return res.status(200).json({ message: "loged in!" }); // username and password match
var payload = { user: user };
// create a token
var token = jwt.sign(payload, 'superSecret', {
expiresIn: 60 * 60 * 24
});
// return the information including token as JSON
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
else {
return res.status(401).json({ message: "Unauthorized" }); // if there is no user with specific fields send
}
}).catch(function (err) {
console.error(err.stack)
return res.status(500).json({ message: "server issues when trying to login!" }); // server problems
});
});
//****************************************************End of Login request **********************************/
//****************************************************Begin of register request******************************/
router.post('/register', function (req, res, next) {
if (JSON.stringify(req.body) == "{}") {
return res.status(400).json({ Error: "Register request body is empty" });
}
if (!req.body.email || !req.body.username || !req.body.password) {
return res.status(400).json({ Error: "Missing fields for registration" });
}
var password = User.generateHash(req.body.password);
User.create({
username: req.body.username,
email: req.body.email,
password: password
}).then(function () {
return res.status(200).json({ message: "user created" });
}).catch(function (err) {
return res.status(400).send({ message: err.message }); //
}).catch(function (err) {
return res.status(400).json({ message: "issues trying to connect to database" });
})
});
//****************************************************End of register request **********************************/
module.exports = router;
If you don't want to use JWT token check for all routes, you can skip those routes.
const url = require('url');
apiRoutes.use((req, res, next) => {
const path = url.parse(req.url).pathname;
console.log(path);
//No JWT token check
if (/^\/register/.test(path)) {
return next();
}
return jwtTokenValidate();
});
function jwtTokenValidate() {
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, app.get('superSecret'), function(err, decoded) {
if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' });
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
}

Express Middleware jsonwebtoken authentication

My server has a registration api that provides a token after registration, and a middleware that authenticates a user's token. I need to register an account to get the token to do something else with my server. However, the middleware blocks my network request because I don't have a token yet.
So how can I create my account and token in this case? Get pass the middleware with some tricks?
Middleware:
// Middleware to verify token, it will be called everytime a request is sent to API
api.use((req, res, next)=> {
var token = req.headers.token
if (token) {
jwt.verify(token, secret, (err, decoded)=> {
if (err) {
res.status(403).send({ success: false, message: "Failed to authenticate user." })
} else {
req.decoded = decoded
next()
}
})
} else {
res.status(403).send({ success: false, message: "No Token Provided." })
}
})
Signin:
// Sign In with email API
api.post('/signInWithEmail', (req, res)=> {
User.findOne({
email: req.body.email
}).select(userFields).exec((err, user)=> {
if(err) {
throw err
}
if (!user) {
res.send({ message: "User doesn't exist"});
} else if (user) {
var validPassword = user.comparePassword(req.body.password);
if (!validPassword) {
res.send({ message: "Invalid Password"});
} else {
var token = createToken(user);
res.json({
success: true,
message: "Login Successfully!",
token: token
})
}
}
})
})
Make a function to check tokens and expose your routes such that whenever you need to call an authenticated route then you'll be checking the token first and then you'll expose the route.
Sample Code
Let's say this is my check token function
function checkToken(req, res, next) {
var x = req.token; //This is just an example, please send token via header
if (x === token)
{
next();
}
else
{
res.redirect(/unauthorized); //here do whatever you want to do
}
}
Now let's use the function for routes.
app.post('/protectedroute', checkToken, routename.functionname);
app.post('/notprotected', routename.functionname);
It's your call if you'd like to have separate routes for different codes or else you can just call specific code block via keeping them in function etc. on the main file i.e. app.js or server.js, whatever you have chosen.
What actually we are doing here is - we are making a middleware of our own to expose our routes through a channel of code blocks or functions.

Resources