Preventing shared session with usergrid authentication - node.js

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...');

Related

How to destroy session?

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.

Connecting a different user using mongoClient connexion pool

I 'm using a MongoClient connexion pool at the top of my app.js node.js back end, it works well:
var db;
MongoClient.connect("mongodb://localhost:27017", function(err, client) {
if (err) throw err;
db = client.db('myDb');
// Start the application after the database connection is ready
app.listen(3000);
console.log("Listening on port 3000");
});
app.post('/getEvaluations', function(req, res) {
db.collection('evaluations').find().toArray(function(err, docs) {
if (err) throw err;
res.send(docs);
});
})
I want to build a html form, for getting the login password, but how can I change the MongoClient connexion with the new login password afterwards ?
For example, as long as John logs in, he needs to have READ rights to be able to call the getEvaluations web service.
Do I have to always make the connexion with no user , then only check the user session inside each of the web services ?
Or Is it possible to change the pool connexion , each time a mongoDb user logs in ( he might only have READ rights)?
Something like this ?
MongoClient.connect("mongodb://john:passwd#localhost:27017", function(err, client) {
if (err) throw err;
db = client.db('myDb');
// Start the application after the database connection is ready
app.listen(3000);
console.log("Listening on port 3000");
});
For example, let's say "John" with the password "passwd" wants to log in, how could I do ? Is there any standard code somewhere using a connexion pool ?
I also use express-session but dont understand how to use it with the connexion pool.
I can't find a mongoDb auth code using the connexion pool. There are some moogoose examples but, it is not the same .
This is the idea I've got :
The user logs in via HTTP, then if the login is ok, so a session is created, but how could i check afterwards if the user only has READ rights during all of his session ?
This is a pseudo code, from a moongoose example, but this is not what i need, i'm using mongoClient.
app.get('/getAuth', function(req, res) {
var email = req.param('email');
var password = req.param('password');
//authenticate input against database
UserSchema.statics.authenticate = function (email, password, callback) {
User.findOne({ email: email })
.exec(function (err, user) {
if (err) {
return callback(err)
} else if (!user) {
var err = new Error('User not found.');
err.status = 401;
return callback(err);
}
bcrypt.compare(password, user.password, function (err, result) {
if (result === true) {
return callback(null, user);
} else {
return callback();
}
})
});
}
})
If somebody has an example code, i would really appreciate it, I don't use moogoose , but mongoClient Thank you.
or maybe, this auth web service would be better :
app.get('/getAuth', function(req, res) {
var user = req.param('user');
var password = req.param('password');
db.authenticate(user, password, function(err, res) {
// callback
});
})
but then, what should I do with the connexion pool ? How could I reload it ?
I can't understand how to do.
EDIT 1: This is what I got for now : I've built a getAuth web service, with a pool connexion starting inside of it, is it the right way to do ?
var db;
app.get('/getAuth', function(req, res) {
var user = "jose";
var password = "passwd";
MongoClient.connect("mongodb://"+user+":"+password+"#localhost:27017", function(err, client) {
if (err) {console.log(err)}
else{
db = client.db('myDb');
// Start the application after the database connection is ready
console.log("correct log in");
}
});
})
how could I use a session now?
EDIT 2 : Seems to be working code with express-session using this doc :
https://codeforgeek.com/manage-session-using-node-js-express-4/
//use sessions for tracking logins
app.use(session({secret: 'ssshhhhh',saveUninitialized: true,resave: true}));
sess ={};
// ---------------------------------------------------------------------AUTH USER
app.get('/getAuth', function(req, res) {
var user = "jose";
var password = "passwd";
MongoClient.connect("mongodb://"+user+":"+password+"#localhost:27017", function(err, client) {
if (err) {console.log(err)}
else{
db = client.db('myDb');
sess = req.session;
/*
* Here we have assign the 'session' to 'sess'.
* Now we can create any number of session variable we want.
* in PHP we do as $_SESSION['var name'].
* Here we do like this.
*/
sess.email = "jose.golo#gmail.com"; // equivalent to $_SESSION['email'] in PHP.
sess.username = "jose"; // equivalent to $_SESSION['username'] in PHP.
res.end('done');
}
});
})
Then, in my getEvaluations web service, i 'm checking if sess contains an email, otherwize, it means that he's not logged in, so he can't access the evaluations node.js web service :
app.post('/getEvaluations', function(req, res) {
if (!sess.hasOwnProperty("email") ){
console.log('not logged in ');
}else{
db.collection('evaluations').find().toArray(function(err, docs) {
if (err) throw err;
res.send(docs);
});
}
})
If you have a better solution, please let me know . This app is front end Ionic 1 app .
Question :
Is it a normal behavior :
I get authenticated inside of firefox, so i can access my evaluations.
Now, I go to chrome, on the same computer , i don't have to authenticate to view the evaluations ?
Is it because it is a user Id based session ?
This is how I would do it:
Let the user log in via a HTTP form using the POST method.
Try and find the user's document inside your mongo database (eg. by username). This will result in a user object containing your user's credentials and whatever rights he/she has.
Compare the credentials with the input provided by the log-in form (which is contained within the request object's body).
If the given input and previously stored credentials are equal to each other you can create a session and assign the user object to it.
Check if there's a session object inside the request when the user navigates to '/getEvaluations'. This session object will contain user object of the currently logged in user.
Respond with your Evaluations object if and only if the user has the appropriate
rights.
You could try out authentication middleware like Passport.js. These will handle the sessions and its user data object for you. Here's an example using the local strategy: https://github.com/passport/express-4.x-local-example

Sails.js : How to return access token after user registration using sails-generate-auth?

I am using sails-generate-auth in my sails.js app. I followed this tutorial to integrate this with my app. When I call localhost:1337/auth/local/register it routes to my callback action in AuthController. My callback action is as follows
callback: function (req, res) {
function tryAgain(err) {
//some validation
}
}
passport.callback(req, res, function (err, user, challenges, statuses) {
if (err || !user) {
return tryAgain(challenges);
}
req.login(user, function (err) {
if (err) {
return tryAgain(err);
}
//Return the access token created by passport instead of success.
res.send("Success");
});
});
I want to replace res.send("Success"); with the access token created by passport. But User.passport seems to be null at this point. How do I get the user's access token at this point?
The User You Get only contains the data from the 'User Collection' which contains the username email and id. The 'Passport' collection is a seperate collection which contains hashed password, ID, userID(which is equal to the ID In the 'User' Collection) and a token. You need to search in the 'passport' collection for the relavent User. Here is the algoritem:
passport.callback(req, res, function (err, user, challenges, statuses) {
if (err || !user) {
console.log(err);
return tryAgain(challenges);
}
req.login(user, function (err) {
if (err) {
console.log(err);
return tryAgain(err);
}
// Mark the session as authenticated to work with default Sails sessionAuth.js policy
req.session.authenticated = true
console.log(user);
var userID = user.id;
Passport.find({user: userID}, function(err, items){
if(err) return err;
console.log(items[0].accessToken);
// Make sure you dont give them any sensetive data
res.json({userData: user, token: items[0].accessToken});
});
// Upon successful login, send the user to the homepage were req.user
//res.redirect('/');
});
});
If you want to use sails built-in sessions, you do not need to send any token to the client, everything is stored server-side in the sessions and it is tied to the user by the sid (session id) cookie, therefore you can redirect to any page.
As long as you have your sessionAuth policy it will check that the user is logged-in before accessing your protected routes.
If you would like to use something like Json Web Tokens (JWT) though, sails-generate-auth / sails-auth do not support it yet

How to implement OAuth to my Nodejs/Sails.js app?

I have a sails.js app that generates API to my client. In order to secure my API I need to implement OAuth2.0 to my sails app. I have started to follow this tutorial: https://www.npmjs.com/package/sails-generate-auth#requirements
But I get all kinds of diffrent errors when every time when I try to lift the server. I also dont understand to where i'm suppose to send my credentials to the server and get the access token. I'm fairly new to Sails.js and just got to know OAuth and I can't find a proper guide on how to implement OAuth.
How can I implement OAuth to my app? please have a detailed answer so that I can fully understand.
UPDATE:
ok so instead I started to follow this guide: https://www.bearfruit.org/2014/07/21/tutorial-easy-authentication-for-sails-js-apps/
and I think I got everything to work as it should(?) when I register an account it saves the data in the database as it should. The login also seems to work properly But I didn't understood how I can access the actuall data like the username and email address after the login redirects me to the homepage? I've tested the login on postman and when i log in I get a cookie. What am I suppose to do with it?
The AuthController generated by sails-generate-auth doesn't add the user details to the session by default so you should add it manually by adding the following line to the callback function in AuthController.js
req.session.user = user;
This is how the callback looks like with the line:
callback: function (req, res) {
function tryAgain (err) {
// Only certain error messages are returned via req.flash('error', someError)
// because we shouldn't expose internal authorization errors to the user.
// We do return a generic error and the original request body.
var flashError = req.flash('error')[0];
if (err && !flashError ) {
req.flash('error', 'Error.Passport.Generic');
} else if (flashError) {
req.flash('error', flashError);
}
req.flash('form', req.body);
// If an error was thrown, redirect the user to the
// login, register or disconnect action initiator view.
// These views should take care of rendering the error messages.
var action = req.param('action');
switch (action) {
case 'register':
res.redirect('/register');
break;
case 'disconnect':
res.redirect('back');
break;
default:
res.redirect('/login');
}
}
passport.callback(req, res, function (err, user, challenges, statuses) {
if (err || !user) {
return tryAgain(challenges);
}
req.login(user, function (err) {
if (err) {
return tryAgain(err);
}
// Mark the session as authenticated to work with default Sails sessionAuth.js policy
req.session.authenticated = true;
req.session.user = user;
// Upon successful login, send the user to the homepage were req.user
// will be available.
res.redirect('/');
});
});
}
You can now use the user details in any of your controllers and views by referring to req.session.user for example twitter provides your user name so you can use req.session.user.username.

Expressjs - How to prevent a user from posting a registration form...?

Is the following an appropriate way to redirect a user if they are trying to POST data to the registration form if they are already logged in or is there a better more secure way? I am preventing them from a GET request to the registration form, but I also want to prevent them from making a POST request thought other means then a form.
The check is:
if(true !== req.session.loggedIn){
}else{
}
In the app.js file:
app.get('/register',register.registration);
app.post('/register',register.doRegistration);
This is the controller file:
var mongoose = require('mongoose');
var User = mongoose.model('User');
exports.registration = function(req,res){
//Redirect the user if they are logged in
if(true !== req.session.loggedIn){
res.render('register', {
});
}else{
res.redirect('/user');
}
}
exports.doRegistration = function(req,res){
//Redirect the user if they are logged in
if(true !== req.session.loggedIn){
User.create({
fullName: req.body.register.fullName,
email: req.body.register.email,
password: req.body.register.password,
createdOn: Date.now()
}, function(err, user){
if(err){
console.log(err);
res.redirect('/register');
}else{
console.log('success');
req.session.user = {
"name": user.fullName,
"email": user.email,
"_id": user._id
};
req.session.loggedIn = true;
res.redirect('/user');
}
});
}else{
res.redirect('/user');
}
}
Firstly, instead of repeating yourself for each route you could simply use some middleware to check if a user is logged in or not and add any logic there:
function ensureNewUser(req, res, next) {
if (req.session.loggedIn) {
// if user is logged in redirect to /user
res.redirect('/user');
} else {
// else next
next();
}
}
Then use that middleware in your route definitions:
app.get('/register', ensureNewUser, register.registration);
app.post('/register',ensureNewUser, register.doRegistration);
Not completely sure what you mean by "more secure way", hard to comment without knowing how you are handling authentication but by "prevent them from making a POST request thought other means then a form" I assume you are talking about CSRF. In which case you should ensure you are using some CSRF middleware app.use(express.csrf()); or if using Express4 something like the csurf module and then ensuring you are sending back the token in the request from your front end.

Resources