How to destroy session? - node.js

I wanna be able to destroy a session after the user logs out. At the moment it's not working as expected. The session doesn't get destroyed.
I'm able to print the console.log() from the logout route.
That's the code I've used so far:
Frontend
const handleLogout = async (e) => {
e.preventDefault();
try {
await fetch("http://localhost:4000/logout", {
method: "GET",
});
} catch (error) {
console.error(error.message);
}
};
Backend
app.get("/logout", (req, res) => {
req.session.destroy((err) => {
if (err) {
return console.log(err);
}
res.send("logged out");
console.log("logged out");
});
});
I don't know if this helps but here is the session:
P.S. I'm using react, node, express and express-session.
Thanks in advance!

req.session.destory() removes the session id from the server-side session store and that will render the client logged out since the session id is removed from the server-side session store and can no longer match the client cookie on future requests. It does not, however, remove the now-orphaned session cookie from the browser.
To do that, you need a res.clearCookie(cookieName) before you do the res.send("logged out"); where you target the name of whatever your session cookie is. That will send the proper header with the response to tell the browser to clear that cookie.

Related

I want to check session data before an AJAX call in nodejs

In my shopping cart I want to check user session data before an ajax call.
If the user is not logged in I want them to redirected to login route. I have created a middleware called verifyLogin to check these login sessions for each time and it really works when not using an ajax. How can I add this middleware to my ajax function ?
Or please give me an another solution for this.
VerifyLogin Middleware
const verifyLogin = (req, res, next) => {
if (req.session.loggedIn) {
next()
} else {
res.redirect('/login')
}
}
Ajax function
function addToCart(proId) {
$.ajax({
url: '/add-to-cart/' + proId,
method: 'get',
success: (response) => {
if (response.status) {
let count = $('#cart-count').html()
count = parseInt(count) + 1
$("#cart-count").html(count)
}
}
})
}
Add to cart route of JS file
router.get('/add-to-cart/:id', (req, res) => {
userHelpers.addToCart(req.params.id, req.session.user._id).then(() => {
res.json({ status: true })
})
})
You can check the specified for session cookie-parameter by document.cookie is it set -- you are loggedin, else -- you are not logged in. Or, you can add extra cookie parameter that indicate if you successfully logged in. And this check you need to put before ajax call. Middleware layer will be working every time for any request to your server. But you need make check only if user trying to add something to cart, for example.

Need assistance with the JWT authenticate process

I am working on a user login project. My front end is React, and my server side is Node/Express js. I am trying to learn about JWT to create protected routes. However, I have gotten stuck when it comes to sending my token (already successfully generated) back to my front end application. I am trying to store the token in a cookie, then send that back to my react side. It is my understanding that I must store the token on the react side before I can access a protected route on my server side, but I am at a loss as to how to proceed to accomplish this. Here is my code for the login post request on my server:
app.post('/userLogin', function(req, res) {
var {usernameLogin, passwordLogin} = req.query;
console.log(req.query);
var validateLogin = `SELECT CustomerID FROM CUSTOMER WHERE Username='${usernameLogin}' AND Password='${passwordLogin}'`;
mysqlConnection.query(validateLogin, (error, result) => {
if(error) {
console.log(error);
} else {
// Checks to see if the result object (CustomerID) exists or not.
if(Object.entries(result).length === 0) {
console.log('sorry');
} else {
console.log(result);
console.log('existing');
const token = jwt.sign({ usernameLogin: usernameLogin}, 'loginKey');
res.cookie('token', token, { httpOnly: true}).sendStatus(200);
console.log(token);
}
}
});
});
and this is my react onSubmit (called login) in my react app. Just as a side note, the "it worked" message successfully is printed to the console, but this is the point at which I do not know how to retrieve and store the token on my client side for future use to access protected routes:
login = (event) => {
event.preventDefault();
console.log(this.state);
fetch('http://localhost:3001/userLogin?usernameLogin=' + this.state.usernameLogin +
'&passwordLogin=' + this.state.passwordLogin, {method: 'POST'}
)
.then(res => {
if (res.status === 200) {
console.log("it worked!!!");
} else {
console.log('there was a problem at line 27');
}
})
};
Any insight would be greatly appreciated!!!
For the client side, you can store the token returned from server side using localStorage property.
Example to set the item: localStorage.setItem("token", <token>);
Example to get the item: let token = localStorage.getItem("token");
Docs: https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Local_storage
PS: Let me know if was enough to solve your question.

Cant get all response data from fetch

So I'm trying to store some info in the session, for later use. But when I fetch it in react, it doesn't all come back. Despite the get route having all of the data.
My thought process is on the serverside, when a user logs in store their id in the session. I'll then have a /userinfo route that dumps all the data i need in json. I can then fetch that /userinfo route and get the data in the response. My code is as follows:
Heres the post code to sign in, I console.log to verify the session is modified. It is.
User.authenticate(req.body.logemail, req.body.logpassword, function (error, user) {
if (error || !user) {
var err = new Error('Wrong email or password.');
err.status = 401;
return next(err);
} else {
req.session.userId = user._id;
console.log(req.session);
return res.redirect('/');
}
});
Then I have this route:
app.get('/userinfo', (req, res)=>{
res.json(req.session);
});
If I simply go to localhost:3000/userinfo the json looks like:
{
"cookie": {
"originalMaxAge": null,
"expires": null,
"httpOnly": true,
"path": "/"
},
"userId": "blahblahblah"
}
so UserID is indeed there.
However, when I finally go to fetch it in react with:
fetch('http://localhost:3000/userinfo')
.then(res => res.json())
.then(data => console.log(data));
All I get back is the cookie. I dont get UserId. I've tried adding UserId to the cookie as well, just to see if it'd work, and likewise I just get the plain cookie.
Solved the issue myself, I didn't even think about it, but I'm making the request from the client, so when I make the request through fetch()
to
app.get('/userinfo', (req, res)=>{
res.json(req.session);
});
the server is returning the session stored on the clientside, which hasnt been updated with userId. So I need to return session data from the serverside, rather than from the client request.
My solution is to create and maintain a User object on the server-side and when I need to access user data, grab it from the user object.

Preventing shared session with usergrid authentication

I have a node site using Usergrid as the backend. I have created a login form screen, however when one user logs in it then shows that user being logged in to all other users who are on the site. If someone else logs in then it will overwrite the previously logged in user. How can I prevent the authenticated session from being shared across all users? I want each user to have their own authenticated session while browsing the site.
Login Code:
app.post("/login", function(req, res) {
if (client.isLoggedIn()) {
console.log("already logged in");
res.send({"status": "success"});
} else {
client.login(req.body.username, req.body.password, function(err) {
logger.debug("After Log In");
if (err) {
logger.error('Login Failed');
logger.error(err);
} else {
logger.debug(client.token);
client.authType = Usergrid.AUTH_APP_USER;
var options = {
method: 'GET',
endpoint: 'users/me'
};
client.request(options, function(err,data) {
if (err) {
console.log(err);
} else {
req.session['current_user'] = data.entities[0];
console.log(data);
console.log("SESSION");
console.log(req.session);
}
res.send({"status": "success"});
});
}
});
}
});
I think the problem is that you are using one instance of the Usergrid.Client object to serve many users. Instead, you should do what Usergrid does: when a user logs in, you give them the Usergrid access_token. You could send it back in a cookie, or in JSON data or whatever you choose.
Then you would expect subsequent HTTP request from the user to include the access_token in the URL or in a cookie, or whatever. On each request you create a new instance of the Usergrid.Client and pass in the token from the user, e.g.
var client = new Usergrid.Client({'token':'abcd5764adf...');

express.js not saving session data on nodeunit tests

Update at bottom!
My node.js server uses express.js to manage sessions. Upon login, I store some user information in req.session. I have a logout endpoint that simply deletes the user data from req.session before sending its response.
With every request the user makes, I use authentication middleware to make sure there is still user data in the session, so deleting user data in the session object should fail any subsequent authentication.
To test my server, I have a nodeunit test that logs in, calls a few endpoints, logs out, and then attempts to call another endpoint. I would expect the last endpoint to fail in authentication because I previously blew away user data. Instead, when I make the last call, my user data is still there. It's as if the logout call that deleted it was not written back into the session store.
Here's my app.js:
app.use(express.cookieParser('secretPassword'));
app.use(express.cookieSession({key: 'someKey'}));
...
app.get('/logout', accounts.logout);
app.get('/account', auth.authenticateSession, accounts.show);
auth.js:
exports.authenticateSession = function(req, res, next) {
if (!req.session.user) {
return res.json(401, {
error: 'Access denied. You must be logged in to make this request.'
});
}
...
}
accounts.js:logout:
exports.logout = function(req, res) {
req.session.user = null;
res.send('Logged out');
};
Unit tests:
step1_logIn : function(test) {
var postData = qs.stringify({
accountname: 'testAcct',
accountpassword: 'hello'
});
ct.postAndCall('/login', null, postData, function(resData, res) {
myCookie = res.headers['set-cookie'];
test.ok(res.statusCode === 200);
test.done();
});
},
step2_logout : function(test) {
ct.getAndCall('/logout', myCookie, function(data, res) {
test.ok(data === 'Logged out.');
test.ok(res.statusCode === 200);
test.done();
});
},
step3_ensureLoggedOut: function(test) {
ct.getAndCall('/account', myCookie, function(data, res) {
test.ok(res.statusCode === 401);
test.done();
});
}
When the tests run, execution goes through logout successfully, then into authenticateSession on the call to /account and at this point, req.session.user still exists! Why!?
Is my cookie store giving me stale data?
Is there a way to force express to save my session data manually, or do I just modify the req.session object and trust that it's going to save it?
Update:
It looks like this problem is directly related to the app middleware surrounding cookies. When I use app.use(express.session()) instead of app.use(express.cookieSession(...)), the session data is properly blown away and my tests pass.
I figured it out. Apparently express.cookieSession(...) is meant to be a set-once type of storage. Subsequent requests will have access to the session data that was initially set, but changing the req.session object won't save back new session data.
To fix the problem, I switched over to use express.session(...) which uses a server-side store for session vars.

Resources