Google user consent page - google-oauth

I'm using passport-google-oauth module in node.js for user authentication in a web app. When a google account is already logged in in a browser and you try to login to the web app via google, passport-google-oauth automatically redirects to the web app as if it has already been authorized and without the google user consent page.
How do I force display of google user consent page every time user logs in via google. I've added approval_prompt but it's still not working.
Please shed some light.
Updates:
authController.js
passport.authenticate('google', { scope : ['profile', 'email'] },
function (err, user) {
req.logIn(user, function (err) {
if (err)
{
console.log(err);
return res.view('site/index',{callouts:callouts.wrongAccess});
}
return res.redirect('/');
});
})(req, res);
},
passport.js
passport.use(new GoogleStrategy({
clientID : configAuth.googleAuth.clientID,
clientSecret : configAuth.googleAuth.clientSecret,
callbackURL : configAuth.googleAuth.callbackURL,
},
function (token, refreshToken, profile, done) {
process.nextTick(function() {
var newUser = {};
var name = {};
var email = profile.emails[0].value;
User.findOne({'email':email}, function (err, user) {
if (err)
{
return done(err);
}
if (user)
{
return done(null, user);
} else
{
User.create(newUser).done(function (err, created){
console.log(created, 'done');
if (err)
{
throw err;
}
return done(null, created);
});
}
});
});
}));

Related

How to store a property in a session with express-session?

I have the following code:
app.post("/login", (req, res) => {
const { username, password } = req.body;
// dummy local database with custome helper functions to look up a user:
db.users.findByUsername(username, (err, user) => {
if (!user) return res.status(403).json({ msg: "No user found!" });
if (user.password === password) {
// Adding properties to session
req.session.authenticated = true;
req.session.user = {
username,
password,
};
console.log(req.session);
// Session is printed in terminal with the above properties. Works fine up to here.
res.redirect("/shop");
} else {
res.status(403).json({ msg: "Bad Credentials" });
}
});
});
I used express-session to create a session and i'm storing it in memory. I created a middleware that would allow a user to access a /shop page only if they're authenticated and have the req.session.authenticated property set to true. For some reason, after they log in, and they're redirected to the /shop page, the properties created in the session are no longer there. Here's the rest of the code:
Authentication middleware:
function ensureAuthentication(req, res, next) {
if (req.session.authenticated) {
// Properties that were added upon logging in are not attached.
return next();
} else {
res.status(403).json({ msg: "You're not authorized to view this page" });
}
}
Shop page
app.get("/shop", ensureAuthentication, (req, res) => {
// Send the user object to the view page:
res.render("shop", { user: req.session.user });
});
Any opinions? Am I missing something here? Does the order of how I have the endpoints written matter?

`Cannot set headers after they are sent to the client ` when I try to login with `passport-google-oauth20`

When I tried to implement Google OAuth into my node app using passport-google-oauth20, I got a problem.
Whenever I attempt the first login to the secrets page with the following code, I fail to authenticate and got redirected to the /login page, also got the error saying Cannot set headers after they are sent to the client at the line serializing the user, even though newUser has been saved in the mongoDB.
However, I can successfully authenticate and login to the secrets page the second login attempt.
What's happening behind the scenes where the error occurs? How can I successfully authenticate the user when the first login attempt?
I referred to this Q&A as well.
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/google/secrets"
},
(accessToken, refreshToken, profile, done) => {
User.findOne({ googleId: profile.id }, (err, foundUser) => {
if (err) return done(err);
if (!foundUser) {
const newUser = new User({
googleId: profile.id
});
newUser.save((err, savedUser) => {
if (err) throw err;
return done(null, savedUser);
});
}
return done(null, foundUser);
});
}
));
passport.serializeUser((user, done) => {
done(null, user.id); ///// The error occurs at this line /////
});
passport.deserializeUser((id, done) => {
User.findById(id, (err, user) => {
done(err, user);
});
});
app.get('/auth/google',
passport.authenticate('google', { scope: ['profile'] }));
app.get(
"/auth/google/secrets",
passport.authenticate("google", {
successRedirect: "/secrets",
failureRedirect: "/login"
})
);
app.get("/secrets", (req, res) => {
if (req.isAuthenticated()) return res.render("secrets");
res.redirect("/login");
});
The issue I see is within the verify callback. Calling return done(null, savedUser) will occur asynchronously. This means that the program will first call return done(null, foundUser) then after the saving call return done(null, savedUser).
To resolve the issue I would recommend refactoring the verify callback to use async/await. This makes it easier to reason about and reduces the chances of race conditions from conflicting callbacks.
Example Refactor:
async (accessToken, refreshToken, profile, done) => {
try {
let foundUser = await User.findOne({ googleId: profile.id });
if (!foundUser) {
const newUser = new User({
googleId: profile.id
});
await newUser.save();
return done(null, newUser);
}
return done(null, foundUser);
} catch (err) {
return done(err);
}
}));

Problem with logout user. Express server api with JWT auth

I'm trying to create a full-stack mern app. I use jwt authentication. I will save the token in local storage and the token will be removed from there with react.
I have tried with req.logout(), req.logOut() and req.session.destroy() and it doesn't work.
Thank you!
const signIn = (req, res) => {
const { email, password } = req.body;
User.findOne({ email: email })
.then((user) => {
if (!user) {
const error = new Error('A user with this email could not be found');
error.statusCode = 401;
throw error;
}
if(!user.authenticate(password)) {
const error = new Error('A user with this email could not be found');
error.statusCode = 401;
throw error;
}
const token = jwt.sign({
email: user.email,
userId: user._id.toString()
}
, 'somesupersecret'
, { expiresIn: '1h' });
res.status(200).json(
{
message: 'User successfully logged in!',
token,
userId: user._id.toString()
});
})
.catch(error => {
if (!error.statusCode) {
error.statusCode = 500;
next(error);
}
})
}
const logOut = async(req, res) => {
try{
await req.logOut();
res.status(200).json(
{
message: 'User successfully logged out!',
});
}
catch(error) {
console.log(error);
}
}
module.exports = {
signUp,
signIn,
logOut
}
I become errors like TypeError: req.logOut is not a function.
This should not be done on the server. Just remove/invalidate your jwt token that is being sent by the client. Generally the token is stored in localStorage and/or cookies. Just delete that token and refresh the page, user will logout.

User in Passport Authentication Custom Callback is always false

I'm trying to use local authentication with Passport and Express, and I have two separate routes to log in: one for the website, which does a redirect, and one for the mobile app which I want to return a JSON object. The redirect route works. However, POSTing the same username and password to the other route receives the JSON response for a failed login. My LocalStrategy is as follows:
passport.use('local-signin', new LocalStrategy(
{passReqToCallback : true},
function(req, username, password, done) {
funct.localAuth(username, password)
.then(function (user) {
if (user) {
console.log("LOGGED IN AS: " + user.username);
req.session.success = 'You are successfully logged in ' + user.username + '!';
return done(null, user);
}
if (!user) {
console.log("COULD NOT LOG IN");
req.session.error = 'Could not log user in. Please try again.'; //inform user could not log them in
return done(null, false, { message: 'User not found' });
}
})
.fail(function (err){
console.log(err.body);
return done(err);
});
}
));
and these are the two places I use it:
app.post('/login', passport.authenticate('local-signin', {
successRedirect: '/',
failureRedirect: '/signin'
})
);
app.post('/api/login', function(req, res, next) {
passport.authenticate('local-signin', function(err, user, info) {
if (err) {
return res.json(user);
}
if (!user) {
return res.json(true);
}
req.logIn(user, function(err) {
if (err) {
return next(err);
}
return res.json(user);
});
})
(req, res, next);
});
I get the success redirect from './login', but './api/login' replies with 'true' (the JSON response I have set for if 'user' is 'false'). This doesn't make any sense to me, but I can't find any problem with the code.
Any idea what the issue here could be? Thanks.

req (request) is not defined for passportjs.use in SailsJS

I want to use req.flash("message" : error ) to support error message callbacks for passportJS inside of SailsJS. However, PassportJS does not handle the below during callbacks: (similar post: PassportJS Custom Authenticate Callback Not Called)
//there is no req found
req.flash("message" , "invalid password");
This usually will be alright if there's something like:
function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
//....
req.flash("message" , "invalid password");
}
But I can't use it inside passport.use.
/services/passport.js
passport.use(new HttpBasicStrategy(
function(username, password, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
// Find the user by username. If there is no user with the given
// username, or the password is not correct, set the user to `false` to
// indicate failure. Otherwise, return the authenticated `user`.
findByUsername(username, function(err, user) {
if (err)
return done(null, err);
if (!user) {
return done(null, false, {
message: 'Unknown user ' + username
});
}
bcrypt.compare(password, user.password, function (err, res) {
if (!res){
--> //there is no req found
--> req.flash("message" , "invalid password");
return done(null, false, {
message: 'Invalid Password'
});
}
var returnUser = {
username: user.username,
createdAt: user.createdAt,
id: user.id
};
return done(null, returnUser, {
message: 'Logged In Successfully'
});
});
})
});
}
));
Is there another way to call req.flash? I'm pretty new at express and sailsjs, please pardon my ignorance.
For sails v0.10.x sails-generate-auth is perfect for this.