Get the ID of authenticated user with passport - node.js

I have a database set up with mongoose and the authentication works via passport (passport-local-mongoose). That works fine, however, I want to get the ID of the current authenticated user so that I can use it as a condition for updating the database. Unfortunately I only know how to check if the user is authenticated in general. Here is the rough structure of what I want to do:
app.post("/updateUser", (req, res) => {
if(req.isAuthenticated()){
Users.updateOne(
{
_id: //get identity of authenticated user
},
{
test: "works!"
},
err => { ... });
}
});

you need to take it by request from user
app.post("/updateUser", (req, res) => {if(req.isAuthenticated()){Users.updateOne({ _id: req.id }, { test: "works!"}, err => { ... }); }});

Related

How to update particular id information in express js

I want to update information from by particular id from a user user collection in MongoDB. I am using ExpressJS.
Right now from my code I can only update only login user information. Being a super admin I want to update user's info by ID. What do I need to do here ?
Here now in my code , when super admin logs in he/she can only update his/her own information. I want the super admin to update user's information
router.put('/edit', checkAuth, function (req, res, next) {
if(req.userData.role === 'superadmin') {
const id = req.userData.userId;
User.findOneAndUpdate({ _id: id }, {$set: req.body}, { new: true }, (err, doc) => {
if (err) return res.send(err.message)
if (doc) return res.send(doc);
})
} else {
res.status(401).send(["Not authorized. Only super admin can update details."]);
}
});
How can I update user's information from the collection ?
You need to specify the ID of another user through the request content, in Express this can easily be achieved with a path parameter:
// Example client request: PUT /edit/507f191e810c19729de860ea
router.put('/edit/:userId', checkAuth, function (req, res, next) {
if (req.userData.role === 'superadmin') {
const id = req.params.userId;
User.findOneAndUpdate({ _id: id }, {$set: req.body}, ...);
} else { /* ... */ }
});
If changing the request path (/edit) is not an option for you, you can opt to specify the target user id through the request body instead (you will also need to update the client request to pass that id along with your new user data):
router.put('/edit', checkAuth, function (req, res, next) {
if (req.userData.role === 'superadmin') {
const { id, ...newUserData } = req.body;
User.findOneAndUpdate({ _id: id }, {$set: newUserData}, ...);
} else { /* ... */ }
});

Is this express-session authentication method secure

Im not sure if this express-session auth method is secure. I encrypt the password using bcryptjs and after encrypting I set the req.session.isLoggedIn = true in admin.js and later check it in events.js by using an if statement. Is the if statement method in events.js secure or somehow breachable? Is there an better option?
I'm using handlebars to render the web pages.
admin.js
bcrypt.compare(pass, user.password).then((doMatch) => {
console.log(doMatch);
//Check if password match
if (doMatch) {
//setting the isLoggedIn value
req.session.isLoggedIn = true;
//Events is the route that requires authentication
return res.redirect('/events');
} else {
res.redirect('/');
}
}).catch((err) => {
console.log(err);
});
events.js
Router.get('/', (req, res) => {
//Checking the if the loggedIn value is true
if (req.session.isLoggedIn) {
Event.find({}, (err, events) => {
res.render('events', {
prods: events,
pageTitle: 'Events',
path: '/events',
hasProducts: events.length > 0
});
}).catch((err) => {
console.log(err);
});
} else {
console.log('User not authenticated');
res.status(404).send({error: 'not authorized!'});
}
});
I don't think this is the best method you should take a look at : http://www.passportjs.org/
They have a good documentation about authentication strategies and registration also many other methods(Facebook login, Twitter...) also there is many tutorials on how you can implement Passport.js
Hope it helps you !

Firebase Admin SDK roles

I am setting up the Firebase Admin SDK in a NodeJS, Express API.
I have added an endpoint that allows me to create a user -
route.post('/create', (req, res) => {
const { email, password } = req.body
fbseAdmin.auth().createUser({ email, password })
.then((userRecord) => {
res.status(200).json({ userRecord })
})
})
What I would like to do however is ensure a user has roles so I can provide Authorisation checks on some services.
I do not understand how I can achieve this though? I was thinking perhaps I add an entry to the realtime database, something like -
users/uid/roles/<role name>: true
However I am not sure if I missing something. Also, if this is the case and I do need to do this, would I do this something like -
route.post('/create', (req, res) => {
const { email, password } = req.body
fbseAdmin.auth().createUser({ email, password })
.then((userRecord) => {
fbseAdmin.database()
.ref('users')
.child(`${userRecord.uid}/roles`)
.set({
admin: true
})
res.status(200).json({ userRecord })
})
})
This seems a little brittle to say the least.
Also, as this entry isn't part of the user object, I would need to look up in the realtime db everytime I want to verify this? Is that correct?
You should look at how to set a custom claim against a user.
route.post('/create', (req, res) => {
const { email, password } = req.body
fbseAdmin.auth().createUser({ email, password })
.then((userRecord) => {
fbseAdmin.auth().setCustomUserClaims(userRecord.uid, { admin: true })
.then(() => {
res.status(200).json({ userRecord })
})
})
})

How to send token in header and redirect in the same time: nodejs

I have the following login-route, where I want to send the token to the client and then redirect to another route. This currently does not work.
How can I do that?
app.post('/login-user', (req, res) => {
user.loginUser(req.body, (err, jResult) => {
if (err) {
res.send(jResult)
}
let token = jwt.sign({
user: jResult,
}, "supersecret")
console.log(token)
res.send(token).redirect('/LimeLINE/chatroom')
})
})
I suggest you to use passport.js middleware, which provide a way to redirect user when they are signed in or when they fail to.
app.post('/login-user', passport.authenticate('your_strategy_name', {
successRedirect : '/limeLINE/chatroom', // redirect to the secure profile section
failureRedirect : '/login-user', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
EDIT
This is my old answer
Use it as a middleware :
var logUser = function(){
return function(req,res,next){
user.loginUser(req.body, (err, jResult) => {
if (err) {
res.send(jResult)
}
let token = jwt.sign({
user: jResult,
}, "supersecret")
console.log(token)
/* Store your token */
next();
})
}
}
app.post('/LimeLINE/chatroom', logUser(), (req, res) => {
/* code for your chat*/
})
To make this mandatory without making the middleware call at each route of you express applicationm dig around the Express Router.

Forcing Sequelize to update req.user in Express route

I have a very simple site that is using Passport JS to create local login strategy to hit a local postgres database using the Sequelize ORM.
The user model looks something like this:
module.exports = function(sequelize, DataTypes) {
return sequelize.define('user', {
id: {
primaryKey: true,
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4
},
email: DataTypes.STRING,
password: DataTypes.STRING,
}, {
classMethods: {
generateHash: function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
},
},
instanceMethods: {
validPassword: function(password) {
return bcrypt.compareSync(password, this.password);
}
},
getterMethods: {
someValue: function() {
return this.someValue;
}
},
setterMethods: {
someValue: function(value) {
this.someValue = value;
}
}
});
}
Everything seems to work just fine. I can sign up using this strategy, log in, and see data.
I also am using Express and have various routes set. The req.user appears to be set correctly, as I can interact with all the fields of this object.
Consider the sample route which works correctly:
app.get('/profile', isLoggedIn, function(req, res) {
res.render('profile.ejs', {
user : req.user
});
});
My serialization / deserialization methods:
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id).then(function(user) {
done(null, user);
}).catch(function(e) {
done(e, false);
});
});
So, as per the Passport JS documentation, the user session seems to be correctly set and hooked into Express.
The trouble is that I cannot update any of the fields in the user object.
If I have the following route:
app.get('/change-email', function(req, res) {
req.user.email = req.body.email;
res.status(200).end();
});
Nothing happens in the database.
This is very similar to this question except it appears with Sequalize, the user object never persists, even after logging out and back in again.
I have also tried: req.session.passport.user.email = req.body.email
Although I didn't think this would fix the problem, I also tried to call login with the new user object, but this generated 500 errors. Which such a limited number of functions that can be called, according to the Passport JS documentation, I'm starting to question if this functionality is even possible.
I'm not sure what to try from here. How can I update my user object using Sequelize?
Any help would be greatly appreciated! Thanks!
// Edit: Rewriting first paragraph to be clearer
When you change any column values in an Instance object you also need to explicitly save the changes to the database to persist them. Since you are already storing the user Instance in req.user via passport.deserializeUser you only need to make a small change to your routing code to do this.
Instead of your current route for /change-email, I suggest:
app.get('/change-email', function(req, res) {
req.user.email = req.body.email;
req.user.save()
.then(function() {
res.status(200).end();
});
});
For more information on how to persist changes to an instance, see this part of the Sequelize documentation.
I know it's a late answer but no wonder someone will pass around this in the near future,
anyway, to get the authenticated user information in req.user with sequelize version 6.* and Express
here is the trick:
//a middleware to verify if a user is authenticated or not
exports.verifyToken = async (req, res, next) => {
let token = req.headers.bearer;
if (!token) {
return res.status(403).send({
message: "No token provided!"
});
}
jwt.verify(token, secretKey, async (err, decoded) => {
if (err) {
return res.status(401).send({
message: "Unauthorized!"
});
}
//$$$$$$$$$ here is everything you want to do $$$$$$$$$$$$$$$
req.user = await Users.findByPk(decoded.id, { raw: true });
next();
});
};
and here is an example where we can use that middleware
.get('/wishlist', auth.verifyToken, (req, res, next) => {
console.log(req.user);
})
the output will be something like this:
{
id: '9313e6e5-7b04-4520-8dbc-d04fad3a0cb1',
fullName: 'Anis Dhaoui',
avatar: 'images/imagelink.jpg',
username: 'anis',
}
and of course, you can modify the output of your findByPk or findOne query using include or exclude see Sequelize docs
https://sequelize.org/docs/v6/core-concepts/model-querying-basics/

Resources