Using hidden input in POST Express - javascript

I need to send a POST to an express controller, using previous data from a get.
I have an email being sent out for a reset password link. User clicks the link, which looks like example.com/user/reset/[reset token]
User enters new password, and then posts the request updating the db.
But I can't seem to post the reset token with the request
This in my GET controller
res.render('resetPassword');
req.body['hiddenToken'] = req.params.token;
But in my POST controller, I can't seem to access that req.body.hiddenToken key
My handlebars code for the hidden input
<input type="hidden" class="form-control" name="hiddenToken">
GET controller
// User Reset GET Route -> verifies token, adds a hidden elm to page, posts data
router.get('/reset/:token', (req, res) => {
PasswordToken.findOne({token: req.params.token})
.then(token => {
if (!token) {
res.render('resetPassword');
req.body['hiddenToken'] = req.params.token;
}
else {
req.flash('error_msg', 'Token not Found, Try Submitting Again');
res.redirect('/user/login')
}
})
});
And in POST, console.log(req.body); returns
{ hiddenToken: '',
password: '123456789',
passwordConf: '123456789'
}
Maybe there is a way in handlebars to inject the params into the value tag?

Setting properties on req.body doesn't make much sense in a route,
as it will be lost afterwards (the request ends). As you said, you could pass the token to handlebars:
res.render('resetPassword', { token: req.params.token });
Then inside handlebars, add it as the input value:
<input type="hidden" class="form-control" name="hiddenToken" value="{{token}}">
Now the token gets sent to the client inside the HTML, then when the user sends the form the token will get sent back as part of the POST requests data.

Related

Why does req.sessions return an empty object instead of the passed value?

I'm learning express.js and I'm stuck on one little problem.
How can I save sessions in the browser so I don't have to log in every time. I use cookie-session. I send the login data downloaded from the form for validation using the POST method to endpoint ./login. After successfully passing the validation, it saves sessions in this way: req.session.admin = 1;, and then using redirect, it redirects to the admin endpoint. After redirecting to ./admin, I try to read if there is a previously saved req.session.admin session. The above action returns me undefined, and the req.session itself returns an empty object {}. I tried console.log on the ./login endpoint and yes, everything is OK i.e. it returns 1 and on the ./admin endpoint it is undfined.
My question to you is: Has anything changed recently in the implementation of cookie-session (although I don't think so, because I do it according to the documentation available on npm), or do I need to install some package besides cookie-session?
Save the session
.post('/login', (req, res) => {
const { body } = req;
if (password === body.password && login === body.login) {
req.session.admin = 1;
res.redirect('/admin');
} else {
res.redirect('/login');
}
});
This is where my problem arises, because the session is not saved and each time the validation fails, I return to login
.all('*', (req, res, next) => {
if (!req.session.admin) {
res.redirect('/login');
return;
}
next();
})
Firstly, req.session.admin = 1 does not save session, but it assigns value to separate request. Each request is independent.
You have to return some information to client (e.g token) for further using. Token should be sent in each request in appropriate header and express should verify it.
What's more you should not send credentials in plain text.
What I recommend is to familiarise yourself with JWT concept https://jwt.io/introduction

How to send user data like Id from post route to get route using redirect in Node JS?

I am working with a basic nodejs website which had a login, register, user routes. Initially the user register and redirected to login, And as he logs in the data is processed in /login post route then he is redirected to user /get route but how to identify the user that have logged in to show user data like profile. So iam stuck with how to identify the user who logged in and how to show his profile data in user /get route using render. As it was a redirect request data cannot be send through it.
I have tried using a undefined variable and using mongodb.
The basic solution for this is to create the session and check whether the user is available.
app.post('/login', function (req, res) {
var post = req.body;
if (post.user === 'user_name' && post.password === 'user_password') {
req.session.user_id = 'user_id';
res.redirect('/user');
} else {
res.send('Bad user/pass');
}
});
You will get the user ID in /user using req.session.user_id.

Sending jwt to the client in Express

First, let me give you an overview of my app, it is fairly simple.
The basic idea is that a user enters his accountname and password into an html form on the /Login page like:
<form action="/Login" method="post" target="_blank">
<label for="fname">First name:</label>
<input type="text" id="name" name="username"><br><br>
<label for="lname">Last name:</label>
<input type="text" id="password" name="password"><br><br>
<input type="submit" value="Submit">
</form>
This works as expected, it makes a post request to /Login transferring username and password.
When the data gets to the server, the server checks if the username and password are valid, if they are a new JSON web token will be created. I use the npm library "bcrypt" for the verification of the account and "jsonwebtoken" for the creation of the token. This looks like this:
const accessToken = jwt.sign(user, process.env.JSON_TOKEN_SECRET, { expiresIn: "10m" })
where the user is just an object, with an id key and a value whatever the name of the account is. If the username was admin it would look like this:
const user = { id: "admin" }
So now I want to deliver this token to the client and I do not know exactly how. I have tried:
res.json({ accessToken })
But all this does is displaying the JSON on the screen. I have also tried a regular res.send() but it won't deliver the token correctly to the user. I want a webtoken authentication so I can use protected routes in my project. If I want to visit a protected route, I get an error, that there is no authentication header, which probably means that the browser didn't receive the token correctly. The route protection is just basic middleware:
const authHeader = req.headers["authorization"] //if console logged authHeader is undefined
const token = authHeader && authHeader.split(" ")[1]
jwt.verify(token, process.env.JSON_TOKEN_SECRET, (err, user) => {
//Some error handling
next()
})
Next, I tried using Postman, where I made a POST request to /Login and got my token in the body of the response back. I pasted the token manually in a Bearer Authorization header and made a GET request to a protected route, which worked.
So how can I send the webtoken correctly to the client?
When you login with POST request it always send token in response so use some function to store that response in localStorage or sessionStorage or after successfully login you could send other request for getting a token from express server.
when user signs in you create json web token. You have a login controller.
const postLogin=(req,res)=>{
// you read the req.body, get username,email, password etc
// then you use email to see if user exists in db
// if user exists, then you verify the password
// if everything works so far you create the token
// token is kinda locked version of your inputs
// when you send it to server, only that server unlocks it with secret-key
let token;
try {
token = jwt.sign({ _id: this._id, email: this.email }, "this-is-secret", {
expiresIn: "1h",
});
} catch (e) {
throw new Error(e.message);
}
res
.status(200)
.header("x-auth-token", token)
.json({ token, userId: existingUser._id.toString() });
}
x-auth=Extended authorization

How to redirect user to a page that requires an access token without exposing token in a URL query

I am trying to implement a way of only allowing authorized admins to access pages with sensitive information within my Web App/API. I am currently using Node.JS with Express to handle routing. Views are generated with Jade/Pug View Engine. CORS requests are handled using the request framework on github. (https://github.com/request/request)
Currently, clients are stored within a MongoDB collection. When they enter their login information, their passwords are compared to a Hash stored in the DB. If everything checks out, a JWT is generated for the user and saved in the client DB and also stored within the browser in localStorage.token.
The user is then redirected to a splash page which has an authentication function as middleware. The authentication function accepts the token in three forms:
var token = req.body.token || req.query.token || req.headers['x-access-token'];
I feel like the way redirection is handled is a bit hacky. I am using window.location = route?token=[token]
Token is handed over to the authentication function within req.query.token, but this is exposed in URL. Here is my login function:
function submitLogIn() {
var credentials = {
email: logInForm.userEmail.value,
password: logInForm.pwField.value
}
fetch('/login', {
headers:{
'Content-Type': 'application/json'
},
method: 'POST',
body: JSON.stringify(credentials)
}).then(function(res){
if(!res.ok) alert("Error!")
else return res.json().then(function(result){
localStorage.token = result.token;
//This is how I'm doing redirecting:
window.location = '/selection?token=' + result.token;
}).catch(function(err){
console.log(err);
throw err;
});
});
Just for reference, this is the front-end route that it's going to at port 3001 which swings it over to 3000 as a reverse-proxy request:
router.post('/login', function(req, res, next) {
request.post({
url: 'http://localhost:3000/authorize',
form: req.body
}).pipe(res)
});
My main question is this: How can I handle redirection at the front-end within fetch calls?
My splash screen is basically a menu of buttons which will take the user to different pages. The pages will contain information that only admins should see. Let's say I want to click on this navigation button. It goes to a /GET route that requires the token to be sent for an OK status. if no token, it returns a 403.
router.get('/main', authorize.adminRequired, function(req, res, next) {
request.get({
url: 'http://localhost:3000/menus'
}, function(response, sensitiveItems) {
return res.render('index', {menu: JSON.parse(sensitiveItems)});
});
});
That authorize.adminRequired function needs a token in the form of a query, x-access-token, or req.body. Can't send a body in a GET request. Don't want to expose in URL, so:
Here's what I tried. I have this redirect fetch call as an onclick function.
function redirectToSensitivePage() {
fetch('/main', {
headers: {
'x-access-token': localStorage.token
},
method: 'GET'
});
};
This gives me a 200, OK. But I don't load the page. The res.render(index) in the route does not fire. The response does contain all of the data, but I am not redirected to the visual representation.
I could do the same hacky redirect using window.location=/main?token=[token], but I don't want to expose the URL token. I could load everything I need into the webpage upon login instead of having separate pages, have those divs hidden out of sight until keypress to make that div the main visible div, but I would rather figure out how to do it via redirect.
I'm still getting my bearings with using Node, so please let me know if I have made any stupid glaring oversights.
Edit: Should I simply try
var token = localStorage.token || req.body.token || req.query.token || req.headers['x-access-token'];
Is there any disadvantage to simply scraping from the localStorage automatically with each request?

node js - How to safely pass token from http get request to html page?

I am working on implementing my own custom password reset that sends an email where the user is taking to a page to reset their password.
So far I have generated a unique token that gets put in an http get request link and emailed to the user.
When the user clicks the link (example mywebsite.com/verifypasswordreset?id=96rZyAWLTu)
I have an express route that gets the token:
//Verify Password Reset
app.get('/verifypasswordreset', function(req, res) {
Parse.Cloud.run('verifyPasswordReset', { token: req.param("id") }, {
success: function(user) {
res.sendFile(path.join(__dirname + '/website/resetpassword.html'));
},
error: function(error) {
res.sendFile(path.join(__dirname + '/website/404.html'));
}
});
});
I then run a Parse cloud code function that validates if the token exists and if so it responds by sending the html that contains a form for resetting the password. (resetpassword.html)
At this point resetpassword.html page's url still has the token embedded in it (mywebsite.com/verifypasswordreset?id=96rZyAWLTu) however, as soon as the user submits the form, it does a http post and posts the new password, leaving the token behind in the link and thus I don't know which token is associated with the password reset?
//Reset Password
app.post('/resetpassword', function(req, res) {
res.send('You sent the password "' + req.body.password + '".');
});
When the user submits the form to change their password, how can somehow get the token from the current url (mywebsite.com/verifypasswordreset?id=96rZyAWLTu) and include it in the http post request so my node js app can read it and knows which token is associated with the password reset?
Or alternatively, is their a better & safer way to keep track of the token?
*note ignore that I am using http I am going to buy an SSL certificate and use https before launch.
I don't see the point of validating the token when you are simply sending a resetpassword.html page. However, the token MUST be validated when actually updating the password for a user. So, here's a slightly modified workflow:
User clicks the link (example mywebsite.com/passwordreset?id=96rZyAWLTu)
app.get('/passwordreset', function(req, res) {
res.sendFile(path.join(__dirname + '/website/resetpassword.html'));
});
Your resetpassword page's URL still has the token embedded. Now, user submits the form, it does a http post and posts the new password.
app.post('/passwordreset', function(req, res) {
Parse.Cloud.run('verifyPasswordReset', { token: req.param("id") }, {
success: function(user) {
//update user's password here
res.send('You sent the password "' + req.body.password + '".');
},
error: function(error) {
res.sendFile(path.join(__dirname + '/website/error.html'));
}
});

Categories

Resources