How to get value from URL using Node.js and Express? - javascript

I am trying to get the token value from the following URL http://localhost:3000/users/reset/e3b40d3e3550b35bc916a361d8487aefa30147c8. I have a get request that checks if the token is valid and redirects the user to a reset password screen. I also have a post request but when I console req.params.token, it outputs :token instead of e3b40d3e3550b35bc916a361d8487aefa30147c8. I am wondering if the form action is correct but don't know how to get the token value from it.
Reset Password Get Request
router.get('/reset/:token', (req, res) => {
console.log(req.params.token) // e3b40d3e3550b35bc916a361d8487aefa30147c8
User.findOne({
resetPasswordToken: req.params.token,
resetPasswordExpires: {
$gt: Date.now()
}
}, (err, user) => {
if (!user) {
req.flash('error_msg', 'The password reset token is invalid or has expired.')
return res.redirect('/users/forgot')
}
res.render('reset')
})
})
reset.ejs
<% include ./partials/messages %>
<form action="/users/reset/:token" method="POST">
<div class="form-group">
<label for="password">Password</label>
<input type="password" id="password" name="password" class="form-control" placeholder="Please enter a password."
value="<%= typeof password != 'undefined' ? password : '' %>" />
</div>
<button type="submit" class="btn btn-primary btn-block">Register</button>
</form>
Reset Password Post Request
router.post('/reset/:token', (req, res) => {
console.log(req.params.token) // :token
User.findOne({
resetPasswordToken: req.params.token,
resetPasswordExpires: {
$gt: Date.now()
}
}, (err, user) => {
if (!user) {
req.flash('error_msg', 'The password reset token is invalid or has expired.')
return res.redirect('/users/forgot')
}
user.password = req.body.password;
user.resetPasswordToken = undefined;
user.resetPasswordExpires = undefined;
user.save(function (err) {
req.flash('success_msg', 'Working.')
return res.redirect('/users/login')
})
})
})

In your form in your HTML, you have this:
<form action="/users/reset/:token" method="POST">
That's going to make the actual URL that gets requested when the form is posted be:
/users/reset/:token
There's no code doing any substitution for the :token here. That's just getting sent directly to the server as the URL.
So, when you then have:
router.post('/reset/:token', (req, res) => {
console.log(req.url); // "/user/reset/:token"
console.log(req.params.token); // ":token"
});
What req.params.token is showing you is whatever is in the URL that's after /users/reset. In your case, that is the literal string ":token". For req.params.token to actually have to token in it, you would have to insert the actual token into the URL so your form tag looks like this:
<form action="/users/reset/e3b40d3e3550b35bc916a361d8487aefa30147c8" method="POST">
Or, you will have to get access to the token some other way such as from the express session, from a cookie, from a field in the form, etc...

To get a URL parameter's value
app.get('/reset/:token', function(req, res) {
res.send("token is " + req.params.token);
});
To get a query parameter ?token=Adhgd5645
app.get('/reset/?token=Adhgd5645', function(req, res) {
res.send("token is " + req.query.token);
});

Related

MONGODB findOne() needs a variable

My function is set to find email brought from /login POST method, but I am failing to declare the variable properly, what is the variable to be inserted into the findOne form on app.get('/data')?
I have:
app.post('/login', function (req, res) {
//console.log(req.body);
const uri = "mongodb+srv://<PRIVATE INFO>.eapnyil.mongodb.net/?retryWrites=true&w=majority";
const client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true, serverApi: ServerApiVersion.v1 });
const users = client.db("data").collection("users");
users.findOne({email:req.body.email},function(err,data){
if(data){
if(data.password==req.body.password){
//console.log("Logged In.");
console.log('Email in DB is: ' + data.email);
console.log('Email in form is: ' + req.body.email);
//res.send({"Success":"Success!"});
res.redirect('/data');
}else{
res.send({"Failed with":"Wrong password!"});
}
}else{
res.send({"Try again":"Email not registered!"});
}
});
});
app.get('/data', (req, res) => {
const users = client.db("data").collection("users");
users.findOne({unique_id:req.session.id})((err, result) => {
if (err) return console.log(err)
// renders index.ejs
res.render('pages/data.ejs', {users: result})
})
});
and on the login.ejs file the following:
<p>Login</p>
</div>
<div class="form-group">
<form id="form" method="POST" action="/login">
<input type="text" name="email" placeholder="E-mail" required="" class="form-control"><br/>
<input type="password" name="password" placeholder="Password" required="" class="form-control"><br/>
<input type="submit" value="Login" class="btn btn-success">
</form>
</div>
Not sure why you are redirecting to the /data method when you already have the user to pass to the view.
Try to redirect in /login directly:
app.post('/login', function (req, res) {
//console.log(req.body);
const uri =
'mongodb+srv://<PRIVATE INFO>.eapnyil.mongodb.net/?retryWrites=true&w=majority';
const client = new MongoClient(uri, {
useNewUrlParser: true,
useUnifiedTopology: true,
serverApi: ServerApiVersion.v1,
});
const users = client.db('data').collection('users');
users.findOne({ email: req.body.email }, function (err, data) {
if (data) {
if (data.password === req.body.password) {
res.render('pages/data.ejs', {users: data})
} else {
res.send({ 'Failed with': 'Wrong password!' });
}
} else {
res.send({ 'Try again': 'Email not registered!' });
}
});
});
Also, I suggest you hash the password that you store in the database using libraries like bcrypt.
Storing credentials in plain text is a bad security practice.
app.get('/data', (req, res) => {
const users = client.db("data").collection("users");
users.findOne({unique_id:req.session.id},((err, result) => {
if (err) return console.log(err)
// renders index.ejs
res.render('pages/data.ejs', {users: result})
}))
});
there is a syntax error after {unique_id:req.session.id}, replace ')' for ',' and close ')' correctly

req.body.email is undefined

I'm implementing a password reset following a tutorial but running into a problem. My req.body.email is coming back undefined. I have body-parser installed and my other routes are running perfectly.
Here is my code summary:
var express = require('express');
var router = express.Router({ mergeParams: true });
var Kids = require('../models/kid');
var User = require('../models/user');
var async = require('async');
var nodemailer = require('nodemailer');
var crypto = require('crypto');
var middleware = require('../middleware');
router.post('/password_reset', function(req, res, next) {
function(token, done) {
User.findOne({ email: req.body.email }, function(err, user) {
console.log(req.body.email); <====== Returning and undefined
console.log(user); <====== Returning as null
if (!user) {
req.flash('error', 'No account with that email address exists.');
return res.redirect('/password_reset');
}
user.resetPasswordToken = token;
user.resetPasswordExpires = Date.now() + 3600000; // 1 hour
user.save(function(err) {
done(err, token, user);
});
});
}
});
and my form
<form action="/password_reset" method="POST" >
<div class="form-group">
<label for="exampleInputEmail1">Enter your email address</label>
<input type="email" class="form-control" id="email" aria-describedby="emailHelp" placeholder="Enter email" required>
</div>
<button type="submit" class="btn btn-warning">Submit</button>
</form>
You have two problems:
You aren't submitting any data
Your <input> has no name attribute, so it can't be a successful control.
If you want req.body.email to have data in it then you need to say name="email".
Related to this, you said <label for="exampleInputEmail1"> but id="email". The for attribute needs to match the id of the element it is labelling. Then aria-describedby="emailHelp" needs to match the ID of the element that is labelling the current element … and isn't needed when you have a real <label>.
You aren't parsing the submitted data
See the documentation for req.body:
Contains key-value pairs of data submitted in the request body. By default, it is undefined, and is populated when you use body-parsing middleware such as express.json() or express.urlencoded().
You haven't used any body-parsing middleware.
Your form is submitting urlencoded data (the default) so use express.urlencoded():
router.use(express.urlencoded())

PassportJS Local Strategy

It's my first time implementing passport strategies (using this tutorial https://scotch.io/tutorials/easy-node-authentication-setup-and-local) and I think I made a small mistake that cause a weird problem. First time login with email and password, no problem (db connected, user login successful) second time with same email and password I get rangeError: Invalid status code: 1 and crash nodemon.
I tried to find more info on this error but there really isn't any out there. I did come across someone else with similiar issue but no one answered his question since October. Anyone care to take a crack at this?
routes.js
app.post('/login', passport.authenticate('local'), function (req, res {
console.log("passport user" + req.user);
res.status(200).json({
user: req.user
});
});
app.get('/user/auth', auth.isAuthenticated, function (req, res) {
if (req.user) {
res.status(200).json({
user: req.user
});
} else {
res.sendStatus(401);
}
});
app.post("/api/user", function (req, res) {
const user = req.body;
console.log(user);
User.findOne({ 'local.email': user.email },
function (err, result) {
if (err) {
console.log(err);
handleError(err, res);
return;
}
if (result) {
res.status(500).send("Email already exists in database");
} else {
var newUser = new User();
newUser.local.password = createHash(user.password);
newUser.local.email = user.email;
newUser.local.name = user.name;
newUser.local.mobile = user.mobile;
newUser.save(function (err, result) {
res.status(201).send("User added to database");
});
}
});
});
auth.js
passport.use(new LocalStrategy({ // redefine the field names the strategy (passport-local) expects
usernameField: 'username',
passwordField: 'password',
passReqToCallback : true
}, function(req, email, password, done) {
// asynchronous
// User.findOne wont fire unless data is sent back
process.nextTick(function() {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
User.findOne({ 'local.email' : email }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(err);
// check to see if theres already a user with that email
if (user) {
return done(null, false, req.flash('signupMessage', 'That email is already taken.'));
} else {
// if there is no user with that email
// create the user
var newUser= new User();
// set the user's local credentials
newUser.local.email= email;
newUser.local.password = newUser.generateHash(password);
// save the user
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
}
var isAuthenticated = function(req, res, next) {
//console.log("isAuthenticated(): ", req.user);
if (req.isAuthenticated()) {
next(); //good moves to the next one
}
else {
res.sendStatus(401);
}
}
return {
isAuthenticated: isAuthenticated,
}
};
user.js
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
// define the schema for our user model
var userSchema = mongoose.Schema({
local: {
id: String,
email: String,
password: String,
name: String,
mobile: String
},
google: {
id: String,
token: String,
email: String,
name: String
}
});
// methods ======================
// generating a hash
userSchema.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
// checking if password is valid
userSchema.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
// create the model for users and expose it to our app
module.exports = mongoose.model('User', userSchema);
html
<div class="panel panel-default">
<div class="panel-body">
<form name='loginForm' ng-submit='ctrl.login()' novalidate>
<div class="form-group">
<input class="form-control" type="text" name="username" placeholder="EMAIL" id="username" ng-model='ctrl.user.username'></div>
<div class="form-group">
<input class="form-control" type="password" name="password" placeholder="PASSWORD" id="password" ng-model='ctrl.user.password'></div>
<div class="form-group">
<input id="submit" name="submit" type="submit" class="btn btn-full btn-block" value="Log In"></div>

Client side routing using jQuery/JavaScript

I'm doing some experimenting in using pure JS/jQuery to handle client-side logic (rather than a framework, like Angular). The problem I'm running into right now is how to log a user in.
Here is my login.hbs file:
<div align="center">
<h2 class="page-header">Account Login</h2>
<form>
<div class="form-group">
{{!-- Username --}}
<input type="text" class="form-control" name="username" placeholder="Username" style="width: 20%">
</div>
<div class="form-group">
{{!-- Password --}}
<input type="password" class="form-control" name="password" placeholder="Password" style="width: 20%">
</div>
<button type="button" class="btn btn-success" onclick="login()">Login</button>
</form>
</div>
This submit request goes to a JS file: login.js:
$(document).ready(function() {
login = () => {
var username = $("[name='username']").val()
var password = $("[name='password']").val()
$.ajax({
type: "PUT",
url: '/login',
data: {
username: username,
password: password
},
success: function(response) {
console.log('Success:')
console.log(response)
},
error: function(error) {
console.log("Error:")
console.log(error)
}
})
}
})
On the server side, I'm accepting this PUT request in index.js:
router.put('/login', function(req, res) {
// Password is not encrypted here
console.log('req.body')
console.log(req.body)
User.findOne({ username: req.body.username }, function(err, user) {
// Password is encrypted here
if (err) throw err
console.log('user')
console.log(user)
bcrypt.compare(req.body.password, user.password, function(err, result) {
if (result) {
var token = jwt.encode(user, JWT_SECRET)
return res.status(200).send({ user: user, token: token })
} else {
return res.status(401).send({error: "Something is wrong."})
}
})
})
})
The current flow is: a user enters their credentials, and those credentials get returned to the success method in my ajax request. The credentials show up in the browser's console (confirming that the server and client are communicating). The question is, how do I route this request to the profile page (or any other page, for that matter)? That is, the user is at http://localhost:3000/login, and after successfully logging in, they are routed to http://localhost:3000/profile, for example, where their personal profile information appears. I'd love to learn both ways of doing this type of routing (server-side and client-side). Thanks!

Authenticating username and password fails - client session

I am trying to adapt some code taken from:
https://github.com/expressjs/express/blob/master/examples/auth/index.js
and incorporate into a login form. The issue is that when running the code and selecting the login button the following is logged in the console:
POST /login
Authenticating undefined:foobar
Authentication failed, please check your username and password. (use "tj" and "foobar")
I'm unsure as to why the user is being returned as undefined when I am inputting tj and foobar as the login and password.
HTML:
<div class="login">
<form method="post" action="/login">
<p><input type="text" name="login" value="" placeholder="Username"></p>
<p><input type="password" name="password" value="" placeholder="Password"></p>
<p class="remember_me">
<label>
<input type="checkbox" name="remember_me" id="remember_me">
Remember me on this computer
</label>
</p>
<p class="submit"><input type="submit" name="commit" value="Login"></p>
</form>
</div>
<div class="login-help">
<p>Forgot your password? Click here to reset it.</p>
</div>
JS:
/**
* Module dependencies.
*/
var express = require('express');
var hash = require('./pass').hash;
var bodyParser = require('body-parser');
var session = require('client-sessions');
var app = module.exports = express();
// dummy database
var users = {
tj: { name: 'tj' }
};
// when you create a user, generate a salt
// and hash the password ('foobar' is the pass here)
hash('foobar', function (err, salt, hash){
if (err) throw err;
// store the salt & hash in the "db"
users.tj.salt = salt;
users.tj.hash = hash;
});
// check if user is logged in, if not redirect them to the index
function requireLogin (req, res, next) {
if (!req.user) {
res.redirect('/');
} else {
next();
}
};
// Authenticate using our plain-object database
function authenticate(name, pass, fn) {
if (!module.parent) console.log('Authenticating %s:%s', name, pass);
var user = users[name];
// query the db for the given username
if (!user) return fn(new Error('cannot find user'));
// apply the same algorithm to the POSTed password, applying
// the hash against the pass / salt, if there is a match we
// found the user
hash(pass, user.salt, function(err, hash){
if (err) return fn(err);
if (hash == user.hash) return fn(null, user);
fn(new Error('invalid password'));
});
}
app.post('/login', function (req, res){
console.log("POST /login")
authenticate(req.body.username, req.body.password, function(err, user){
if (user) {
// Regenerate session when signing in
// to prevent fixation
req.session.regenerate(function(){
// Store the user's primary key
// in the session store to be retrieved,
// or in this case the entire user object
req.session.user = user;
/*req.session.success = 'Authenticated as ' + user.name
+ ' click to logout. '
+ ' You may now access /restricted.';*/
res.redirect('/queryInterface.html');
});
} else {
console.log('Authentication failed, please check your '
+ ' username and password.'
+ ' (use "tj" and "foobar")');
res.redirect('/');
}
});
});
You are seeing the user as undefined because you are using req.body to access an undefined input field.
You are authenticating with req.body.username, but your input field has the name login.
req.body is populated with the names of your input fields. Your input should look like this when trying to access the username by req.body.username.
<input type="text" name="username" value="" placeholder="Username">

Categories

Resources