req.isAuthenticated() never evaluates to true - javascript

I'm trying to implement user authentication as below:
userRouter.post("/login", passport.authenticate("local", { session: false }), (req, res) => {
if (req.isAuthenticated()) {
const { _id, username } = req.user;
const token = signToken(_id);
res.cookie("access_token", token, { httpOnly: true, sameSite: true });
res.status(200).json({ isAuthenticated: true, user: { username } });
}
});
But to be able to add some custom messages I'm using the alternative below:
userRouter.post('/login', (req, res, next) => {
passport.authenticate('local',{ session: false }, (err, user, info) => {
if (req.isAuthenticated()) {
const { _id, username } = req.user;
const token = signToken(_id);
res.cookie("access_token", token, { httpOnly: true, sameSite: true });
res.status(200).json({ isAuthenticated: true, user: { username } });
}
if (err) return next(err)
if (info)
res.status(400).json({ message: { msgBody: info.message, msgError: true } });
})(req, res, next);
});
However, in the second alternative, it seems like req.isAuthenticated() is never evaluated to true.
Can anyone help me understand why?
Thanks

The passport docs say "Note that when using a custom callback, it becomes the application's responsibility to establish a session (by calling req.login()) and send a response." (http://www.passportjs.org/docs/authenticate/)
With the follow code as an example:
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
I wonder if it says you are not authenticated because you need to call the login method?

Related

passport.js how to make Multiple req.user

In my app there are two types of users (seller and buyer) Authentication works fine but I am not able to create seperate req.user so that i can use them in my ejs files, I am new to coding thankyou for helping me out.
both users are diffrent in database but for session they are the same user.
app.js
passport.use('userLocal', new LocalStrategy(User.authenticate()));
passport.use('sellerLocal', new LocalStrategy(Seller.authenticate()));
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (user, done) {
if (user!=null)
done(null, user);
});
app.use((req, res, next) => {
res.locals.currentUser=req.user;
res.locals.success=req.flash('success');
res.locals.error=req.flash('error');
next();
})
Seller.js
route.post('/register/seller', catchAsync(async (req, res, next) => {
try {
const { proprietorname, companyname, address, contactnumber, email, username, password }=req.body;
const seller=new Seller({ proprietorname, companyname, address, contactnumber, email, username });
const registeredSeller=await Seller.register(seller, password);
req.login(registeredSeller, err => { //after registering it logins the registered user
if (err) return next(err);
req.flash('success', 'SELLER LOGIN');
res.redirect('/products');
})
} catch (e) {
req.flash('error', e.message);
res.redirect('/register/seller')
}
}));
route.get('/login/seller', (req, res) => {
res.render('users/sellerLogin')
})
route.post('/login/seller', passport.authenticate('sellerLocal', { failureFlash: true, failureRedirect: '/login/seller', keepSessionInfo: true, }), (req, res) => { //a authentication middleware by passport you can add google fb twiiter too insted of just local
req.flash('success', 'yooooo');
const redirectUrl=req.session.returnTo||"/products";
delete req.session.returnTo;
res.redirect(redirectUrl);
});
user.js
route.post('/register/buyer', catchAsync(async (req, res, next) => {
// res.send(req.body);
try {
const { email, username, password }=req.body;
const user=new User({ email, username });
const registeredUser=await User.register(user, password); //registering user
req.login(registeredUser, err => { //after registering it logins the registered user
if (err) return next(err);
req.flash('success', 'Welcome to SnapBuy');
res.redirect('/products');
})
} catch (e) {
req.flash('error', e.message);
res.redirect('/register/buyer')
}
}));
route.get('/login/buyer', (req, res) => {
res.render('users/buyerLogin')
})
route.post('/login/buyer', passport.authenticate('userLocal', { failureFlash: true, failureRedirect: '/login/buyer', keepSessionInfo: true, }), (req, res) => { //a authentication middleware by passport you can add google fb twiiter too insted of just local
req.flash('success', 'Welcome Back');
const redirectUrl=req.session.returnTo||"/products";
delete req.session.returnTo;
res.redirect(redirectUrl);
});
route.get('/logout', (req, res, next) => {
req.logout();
req.flash('success', "Goodbye!");
res.redirect('/products');
});

I can't get passport remember me working with express router

I'm using passport remember me with express router. It's not working properly when I use:
router.route("/login).(someController().postlogin)
Then the authentication is not working as it doesn't generate the token.
But when I use the app.post then it's working.
Working code:
app.post('/login', passport.authenticate('local', { failureRedirect: '/login' }),async function(req, res, next) {
// issue a remember me cookie if the option was checked
if (!req.body.remember_me) { return next(); }
var token = utils.randomString(64);
try {
const tokenData= await Token.create({ userId: req.user.id, token });
res.cookie('remember_me', token, { path: '/', httpOnly: true, maxAge: 604800000 }); // 7 days
return next();
} catch (error) {
return next();
}
},
function(req, res) {
res.redirect('/');
});
But when I use the same code with router it's not working:
postLogin: (req, res) => {
passport.authenticate('local', { failureRedirect: '/login' }),async function(req, res, next) {
// issue a remember me cookie if the option was checked
if (!req.body.remember_me) { return next(); }
var token = utils.randomString(64);
try {
const tokenData= await Token.create({ userId: req.user.id, token });
res.cookie('remember_me', token, { path: '/', httpOnly: true, maxAge: 604800000 }); // 7 days
return next();
} catch (error) {
return next();
}
},
function(req, res) {
res.redirect('/');
}
},
I am using:
http://www.passportjs.org/packages/passport-remember-me/
http://www.passportjs.org/
finally it's working but there is a new issue ,Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client cant understand how to fix it.
postLogin: async (req, res, next) => {
// passport.authenticate('local', { failureRedirect: '/login' })
passport.authenticate('local', {}, async function (err, user, info) {
if (err) {
console.log(error);
return next(err);
}
if (!user) {
console.log("NO USER");
return res.redirect('/login');
}
if (req.body.remember_me) {
var token = utils.randomString(64);
await Token.create({
token: token,
userId: user.id,
}).then((token) => {
if (token) {
res.cookie('remember_me', token.token, { path: '/', httpOnly: true, maxAge: 604800000 }); // 7 days
return next();
}
}).catch((err) => {
console.log(err)
return done(err);
})
}
req.logIn(user, function (err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res, next);
},

Node.js passport authentication ignores controller function

If passport returns the user { status: 200 }:
passport.js
...
return done(null, rows[0], { status: 200 });
...
I want the controller 'controllerLogin.login' to be called:
routs/index.js
const express = require('express');
const passport = require('passport');
const passportConf = require('../passport');
const controllerLogin = require('../controllers/login');
...
router.route('/v1/login')
.post( function(req, res, next) {
passport.authenticate('local-login', function (err, user, context = {}) {
if (err) {
console.log(err);
}
if (context.status === 429) {
return res.status(429).send({ status: 429, success: false })
}
if (context.status === 401){
return res.status(401).send({ status: 401, success: false })
}
next();
//return;
})(req, res, next);
}, controllerLogin.login );
But I can't reach the controller 'controllerLogin.login'. What am I missing and how to execute 'controllerLogin.login'?
The below was working, but I need the upper version.
const passLogin = passport.authenticate('local-login', { session: false, failWithError: true });
router.route('/v1/login')
.post( passLogin, function(err, req, res, next) {
return res.status(401).send({ status: 401, success: false })
}, controllerLogin.login );
Edit: What works ...
router.route('/v1/login')
.post( function(req, res, next) {
passport.authenticate('local-login', { session: false, failWithError: false }, function (err, user, context = {}) {
if (err) {
console.log(err);
}
if (context.statusCode === 429) {
return res.status(429).send({ status: 429, success: false, message: { name: 'Rate Limit Error' } })
}
if (context.statusCode === 401){
return res.status(401).send({ status: 401, success: false, message: { name: 'Authentication Error' } })
}
// this works getting user information
console.log('user:');
console.log(user);
next();
})(req, res, next);
}, /*controllerLogin.login*/ (req, res) => { res.status(200).json({just: 'testing'})} );
controller/login.js
module.exports = {
login: async (req, res, next) => {
// Can't access user information via 'req.user' anymore
console.log('req.user:');
console.log(req.user);
/* .. How to access user information here? .. */
res.status(200).json({just: 'testing'})
}
}
It sounds like controllerLogin.login wants req.user, but that is not being set. So try doing that manually in the callback you pass in to passport's authenticate function.
router.route('/v1/login')
.post( function(req, res, next) {
passport.authenticate('local-login', { session: false, failWithError: false }, function (err, user, context = {}) {
if (err) {
console.log(err);
return next(err); // might want to add this line to handle errors?
}
if (context.statusCode === 429) {
return res.status(429).send({ status: 429, success: false, message: { name: 'Rate Limit Error' } })
}
if (context.statusCode === 401){
return res.status(401).send({ status: 401, success: false, message: { name: 'Authentication Error' } })
}
if(!user) {
// might want to handle this separately? user not found?
//return next('User not found');
}
// this works getting user information
console.log('user:');
console.log(user);
req.user = user;
next(); // this moves us on to controllerLogin.login
})(req, res, next);
}, controllerLogin.login);
Then in controller/login
module.exports = {
login: (req, res) => {
// remove user logging once this works, don't want to log sensitive info (!)
console.log('req.user in controller/login:')
console.log(req.user)
// user logic here
res.status(200).json({status: 200, success: true})
}
}
It's worth taking a look at passportjs docs under the "Custom Callback" section. That example doesn't pass along to another function as you are doing, but it can help to see another approach.

passport-jwt returns unauthorized when I go to /admin page on my web app

I am trying to get the user logged in using passport and jwt token. I manage to generate jwt token successfully but when I go to /admin page by typing in the browser I am getting the unauthorized message. I have read all the answer here but they aren't helping me out.
My passport.js file
try {
passport.use('signin', new LocalStrategy(
function(username, password, done) {
Users.findOne({username: username}, (err, user) => {
if (err) { return(err)}
if(!user) { return done(null, false, { message: 'Incorrect username.' })}
if (!checkUser(password, user.password)) { return done(null, false, { message: 'Incorrect username.' }); }
return done(null, user);
});
}
))
} catch (error) {
return done(error);
}
passport.use(new JWTstrategy({
secretOrKey: config.get('jwt.tokenKey'),
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken()
}, async(token, done) => {
try {
return done(null, token.user);
} catch (err){
done(err);
}
}))
My login-controller file: -
router.post('/', (req, res) => {
passport.authenticate('signin', {session:false}, async(err,user,info) => {
try {
if (err || !user) {
console.log(err);
}
req.login(user, {session:false}, err => {
if (err) res.send(err);
const body = { username: user.username};
const token = jwt.sign( {user:body}, config.get('jwt.tokenKey'));
res.json({ success: true,
token: 'Bearer ' + token });
});
} catch (error) {
return next(error);
}
})(req, res);
})
My admin page file: -
router.get('/', passport.authenticate('jwt', { session: false }), function (req,res) {
res.render('./../views/admin/admin.pug');
})

How to send an object and authenticate with passport at the same time

As vague as the question seems, I need a way to send a json object and also authenticate with passport at the same time. The object is req.isAuthenticated which will be picked up with axios later in the frontend as a checkpoint. That's what I intend. So far with the code below, the object will not be sent.
app.get('/login',
passport.authenticate('saml', {
successRedirect: '/assert',
failureRedirect: '/',
}),
(req, res) => {
res.json({isAuthenticated: req.isAuthenticated()})
}
);
Here is example sample from my project:
authorizeLocal: (req, res, next) => {
passport.authenticate('local-auth', (err, user, info) => {
if (info) console.log(info);
if (err) return next(err);
if (!user) return res.status(200).send({failReason: 'wrong login/password'});
req.logIn(user, err => {
if (err) return next(err);
delete user.password;
req.session.cookie.maxAge = 24 * 60 * 60 * 1000; // 24 hours
if (user.role === 'operator') {
user.status = 'Online';
operatorsService.setStatus('Online', user.id)
.then(result => {
dialogsService.getWaitingDialogs();
user.work_time = result;
res.status(200).send(user);
})
.catch(() => res.status(200).send({failReason: 'Service error'}));
} else res.status(200).send(user);
});
})(req, res, next);
},
There you can see passport req.logIn, which (needs local-auth strategy or tother in your case) performs auth and if success fires callback logic. Deeper you can have any user/object get/generation logic. I left my case for example. OperatorsService.setStatus returns some time data, which is stored to user (user is got as callback param after strategy logic run) end sent as response. You can add user.isAuthenticated = req.isAuthenticated(); there.
So you'll have smth like:
auth.route.js
app.get('/login', authCtrl.authorizeLocal);
authCtrl.js
authorizeLocal: (req, res, next) => {
passport.authenticate('saml', (err, user, info) => {
if (info) console.log(info);
if (err) return next(err);
// if (!user) return res.status(200).send({failReason: 'wrong login/password'});
req.logIn(user, err => {
if (err) return next(err);
res.status(200).send({isAuthenticated: req.isAuthenticated()}));
});
})(req, res, next);
},

Categories