How to set isAdmin variable in passport local strategy? - javascript

I am trying to create a middleware to allow only admin access to certain routes in my node.js project. My middleware currently looks like this.
function adminAuth(req, res, next){
if(req.user.isAdmin){
return next();
} else {
res.redirect("/");
}
}
The issue is that req.user.isAdmin is never recognized even if the user data contains isAdmin: true. I believe that I need to define user.isAdmin in my passport strategy but I am not sure how to do it. Any help would be greatly appreciated!
here is my local strategy
(async function addUser() {
let client;
try {
client = await MongoClient.connect(url);
const db = client.db(dbName);
const col = db.collection('users');
const user = await col.findOne({ email });
debug('Found user by email');
debug(user);
if (!user) {
req.flash('error', 'The username or password is wrong');
done(null, false);
} else {
const match = await bcrypt.compare(password, user.password);
if (match) {
done(null, user);
} else {
req.flash('error', 'The username or password is wrong');
// we pass null because it did not error, just failed
done(null, false);
}
}
} catch (e) {
debug(e.stack);
}
client.close();
}());
}
));
};
Here is my passport.js
passport.serializeUser((user, done) => {
done(null, user.email);
});
passport.deserializeUser((email, done) => {
done(null, email);
});
};

Related

Getting req.user undefined in passportjs?

I have configured passportJS with node express app but when I make login/register request then in that case req.user is undefined any idea what is wrong am I missing something in configuring passport js? I have used express-session and mongoDB store for storing sessions
passport-config.js:
const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy;
const User = require("./Models/userSchema");
passport.use(
new LocalStrategy(
{
usernameField: "email",
passwordField: "password",
},
async (email, password, done) => {
try {
const user = await User.findOne({ email });
// Username/email does NOT exist
console.log("user in config", user);
if (!user) {
return done(null, false, {
message: "Username/email not registered",
});
}
// Email exist and now we need to verify the password
const isMatch = await user.isValidPassword(password);
return isMatch
? done(null, user)
: done(null, false, { message: "Incorrect password bro" });
} catch (error) {
done(error);
}
}
)
);
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(async function (id, done) {
const user = await User.findById(id);
done(null, user);
});
server.js file: https://pastebin.com/NfpvXSFf (see line 39)
I would try:
async (req, res) => {
{email, password, done} = req.body;
(you need a body-parser for that)

Invalid Credentials Bcyrpt.compare()

const express = require('express');
const router = express.Router();
const auth = require('../../middleware/auth');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('config');
const { check, validationResult } = require('express-validator');
const User = require('../../models/User');
// #route Get api/auth
// #desc Test route
// #access Public
router.get('/', auth, async (req, res) => {
try {
const user = await User.findById(req.user.id).select('-password');
res.json(user);
} catch(err) {
console.error(err.message);
res.status(500).send('Server Error')
}
});
// #route POST api/auth
// #desc Authenticate User And Get Token
// #access Public
router.post('/',
[
check('email', 'Please include a valid email').isEmail(),
check('password', 'Password is required').exists()
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array()});
}
const { email, password } = req.body;
try {
// See if user exists
let user = await User.findOne({ email})
if (!user) {
return res
.status(400)
.json({ errors: [ { msg: 'Invalid Credentials Email' } ] });
}
// Make Sure Password matches
const isMatch = await bcrypt.compare(password, user.password);
if(!isMatch) {
return res
.status(400)
.json({ errors: [ { msg: 'Invalid Credentials Password' } ] });
}
const payload = {
user: {
id: user.id
}
}
jwt.sign(
payload,
config.get('jwtSecret'),
{ expiresIn: 360000 },
(err, token) => {
if(err) throw err;
res.json({ token });
}
);
} catch(err) {
console.error(err.message);
res.status(500).send('Server error')
}
});
module.exports = router
In my database I have email and password
in my postman when i make POST request to https://localhost:5000/api/auth
the email is correct however I keep getting password is not correct with this const isMatch = await bcrypt.compare(password, user.password);
if(!isMatch) {
return res
.status(400)
.json({ errors: [ { msg: 'Invalid Credentials Password' } ] });
}
i console logged both password and user.password and it is the same value, i dont understand why !isMatch is keep getting triggered
can anyone help me
The syntax of bcrypt.compare() is:
bcrypt.compare(plaintextPassword, hash)...
The first parameter is plaintext password and second is hash of the real password so it will not be the same value. As you mentioned that your password and user.password is the same value, I guess you forgot to hash user password before saving it to the DB. Please check the docs for more details.

How do I logout with JWT, passport Authentication (NodeJS)?

I am new to NodeJS and I have been following a tutorial. I made some changes to the tutorial code in order to allow users to login by typing in their username or email instead of just username.
passport.use(
new LocalStrategy(
(username_or_email, password, done) => {
User.findOne({ email: username_or_email }, (err, user) => {
if (err) {
return done(err);
console.log(err);
}
if (!user) {
User.findOne({ username: username_or_email }, (err, user) => {
//If there is an error
if (err) {
return done(err);
console.log(err);
}
//If there is no user
if (!user) {
return done(null, false);
} else {
user.comparePassword(password, done);
}
});
} else {
user.comparePassword(password, done);
}
});
}
)
The code above works well and allows users to type in username OR password to login.
Now when I follow the tutorial for how to logout, their method doesn't work for me.
I have a route like this, it is supposed to log a user out.
userRouter.get(
'/logout',
passport.authenticate('jwt', { session: false }),
(req, res) => {
res.clearCookie('access_token');
res.json({ user: { username: '', role: '' }, success: true });
}
);
When I go to it in Postman it says "Unauthorized" and does not return anything else.
I believe it could be something to do with my 'jwt' set up, shown below.
passport.use(
new JwtStrategy(
{
jwtFromRequest: cookieExtractor,
secretOrKey: 'NoobCoder',
},
(payload, done) => {
console.log(payload);
User.findById({ _id: payload.sub }, (err, user) => {
if (err) {
return done(err, false);
console.log('1');
}
if (user) {
return done(null, user);
console.log('2');
} else {
return done(null, false);
console.log('3');
}
});
}
)
);
This is the cookieExtractor function that I use for jwtFromRequest
const cookieExtractor = (req) => {
let token = null;
console.log(token);
if (req && req.cookies) {
token = req.cookies['access_token'];
}
return token;
};
The only console output I get is the console.log in the cookieExtractor.
Which makes me believe that that must be the point of failure. It is a "null" output as expected, and if I console.log the token, I get the current logged in users token. I believe the jwtFromRequest calls the cookieExtractor function but fails at some point soon after.

How to authenticate JWT Tokens with Passport.js generated for multiple roles?

I've a use-case. My application has multiple users where not all users have the access to all the functionalities in the application. I have to restrict them from accessing the application. For that, I've been writing logic that works as the gateway.
I've created different rules which provides a different kind of authentication methods.
When a user log in to the application, will generate a JWT token upon successful login. That token will be authenticated using the rules given.
Here's my code.
server.js
global.app = new require("express")();
global.passport = require("passport");
require("./bin/kernal");
require('./bin/passport');
----Remaining Code----
TokenAuth.js
var passport = require("passport");
require("../../bin/passport");
module.exports= function (req, res, next) {
passport.authenticate('jwt', function (error, user) {
console.log(user);
if (error) return next(error);
if (!user) return res.status(401).json({"error":"Incorrect data", "status":401, "success":false});
//req.user = user;
next();
})(req, res, next);
};
module.exports.UserAuth = function(req, res, next){ // Error Web Response
passport.authenticate('user_rule', function (error, user) {
if (error) return next(error);
if (!user) return res.status(500).json({"message":"No User found", "status":500, "success":false});
//req.user = user;
next();
})(req, res, next);
};
Passport.js
var passport = require("passport");
app.use(passport.initialize());
app.use(passport.session());
require('../app/middlewares/TokenAuth')
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findOne({_id: id}, function (err, user) {
done(err, user);
});
});
var JwtStrategy = require('passport-jwt').Strategy;
var ExtractJwt = require('passport-jwt').ExtractJwt;
var options = {};
options.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
options.secretOrKey = process.env.jwt_secret;
passport.use(new JwtStrategy(options, function (payload, done) {
console.log(payload)
User.findOne({_id: payload._id}, function (error, user) {
if (error) return done(error, false);
if (!user) return done(null, false);
// req.auth_user = {"_id":user._id,"email":user.email,"name":user.name,"status":user.status}
done(null, user);
});
}));
passport.use('user_rule', // UserAuth in TokenAuth.js has to use this functionality
new JwtStrategy(options,async function (payload, done) {
console.log(payload)
let err, authUser,companyResource;
[err,authUser] = await to(CompanyContacts.findById(payload._id).populate('company',
["accountid","company_name","email","status"]).lean().exec());
if (err) return done(err, false);
if (!authUser) return done(null, false);
let user= authUser;
if(user.status==true && user.company.status==true){
req.auth_user = {"_id":user._id,"email":user.email,"name":user.fullname,status:user.status,isPrimary:user.primarycontact};
req.auth_company=user.company._id;
req.isAdmin=false;
req.auth_role=user.role;
done(null, user);
}else{
return done(err, false);
}
})
);
user_api.js
router.get("/all/menus",TokenAuth,MenuController.getAllDropDowns);
router.post("/company/user/signin", TokenAuth.UserAuth, AuthController.customerlogin);
Here, when the post api get executed, only the user who gets authenticated has to get the access that api.
But the problem here is, whenever I use this authentication methods, I'm getting the error specified below.
{
"error": "Incorrect data",
"status": 401,
"success": false
}
As per my knowledge, the data is not going into the Passport.js file to get authenticate.
Is this approach good, or do I need to make any changes in this code to make it work?

how to send error message to client?

I am using passport with local strategy .but I want to send message and status when credential is not match or (user is not exit is DB)
here is code
router.js
const passport = require('passport');
const passportConfig = require('../passport')
const passportSignIn = passport.authenticate('local', { session: false });
router.route('/login',)
.post(passportSignIn,controller.login)
on controller file
login: async (req, res, next) => {
console.log(req.body);
res.json({status:200})
}
passport.js
passport.use(new LocalStrategy({
usernameField: 'email'
}, async (email, password, done) => {
const user = await db.User.findOne({where: {email: email}});
if (!user) {
return done(null, false,{message:"No user exit"});
}
const isMatch = await bcrypt.compare(password, user.dataValues.password);
console.log(isMatch, 'isMatch');
if (!isMatch) {
return done(null, false);
}
// Otherwise, return the user
done(null, user);
}))
Client code
when user click on login button it goes to /login path first it goes to passportSignIn function or below function.
`new LocalStrategy({
usernameField: 'email'
}, async (email, password, done) => {`
now if user not found I want to send this message on the client as the response ("No user exit")
return done(null, false,{message:"No user exit"});
You have to update your login controller, like so:
login: (req, res, next) => {
console.log(req.body);
passport.authenticate('yourStrategy', function(err, user, info) {
if (err) {
return res.status(500).json("Internal Server Error");
}
if (!user) {
// This 'info' variable below would be - { message: "No user exit" }
// as you passed in the done() callback as the third param
return res.status(404).json(info.message);
}
}
}

Categories