Github oAuth with PassportJS not authenticated - node.js

I'm trying to use passportJS to authenticate with the github-strategy. I've previously used passportJS with success, but not with the github-strategy, though I don't figure it should be much different. /viewData is the route in which I'm testing for authentication.
The strategy authenticates successfully and puts the data in the DB and when I serialize and deserialize the user data is in fact there. The problem comes when I try to check in any route after if the req.isAuthenticated() or even if req.session.passport.user exists and it returns false and undefined respectively. The weird thing the same check in app.js after I've redirected through /testAuth the authentication logs correctly with the true and id#. So I feel like its some issue with express-session or the passport integration with that that's breaking it, but I can't find it. I've been on this for a long time so hopefully someone can help me.
app.use(cookieParser('test'));
app.use(session({
secret: 'test',
resave: false,
saveUninitialized: true
}));
//pasport setup
app.use(passport.initialize());
app.use(passport.session());
// Passport init
passport.use(new GithubStrategy({
clientID: config.github.clientID,
clientSecret: config.github.clientSecret,
callbackURL: config.github.callbackURL },
function(accessToken, refreshToken, profile, done) {
User.findOne({ oauthID: profile.id }, function(err, user) {
if(err) {
console.log(err); // handle errors!
}
if (!err && user !== null) {
done(null, user);
} else {
user = new User({
oauthID: profile.id,
name: profile.displayName,
created: Date.now()
});
user.save(function(err) {
if(err) {
console.log(err); // handle errors!
} else {
console.log("saving user ...");
done(null, user);
}
});
}
});
}
));
// test authentication
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
console.log("Not Authenticated", req.user);
res.redirect('/');
}
app.get('/testAuth', ensureAuthenticated, function(req, res){
User.findById(req.session.passport.user, function(err, user) {
if(err) {
console.log(err); // handle errors
} else {
res.redirect('/viewData');
}
});
});
//auth pages
app.get('/auth/github',
passport.authenticate('github'),
function(req, res){});
app.get('/auth/github/callback',
passport.authenticate('github', { failureRedirect: '/' }),
function(req, res) {
res.redirect('/testAuth');
});
// serialize and deserialize for session
passport.serializeUser(function(user, done) {
console.log('serializeUser: ' + user);
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user){
console.log('deserializeUser: ' + user);
if(!err) done(null, user);
else done(err, null);
});
});

So this is a weird one, but I was fixing something else that was weird and in doing so solved this problem. I just moved my
app.use('/', index);
app.use('/viewData', viewData);
To below all the passport code and it works now.

Related

Passport req.isAuthenticated() doesn't work

I'm using express-session and passport to authenticate.
Here's my module :
(updated)
passport.use(new LocalStrategy(
function(username, password, done) {
LamAdmin.findOne({ email: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Incorrect username' }); }
if (!comparePassword(user.password, password)) { return done(null, false, { message: 'Incorrect password' }); }
return done(null, user);
});
}
));
router.post('/login', passport.authenticate('local',{
successRedirect: '/p/dashboard',
failureRedirect: '/p',
failureFlash: true
}));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
LamAdmin.findById(id, function (err, user) {
done(err, user);
});
});
function checkAuth(req,res,next) {
if (req.isAuthenticated()) {
next();
} else {
res.redirect('/p');
}
}
// //DOES NOT WORK WITH CHECKAUTH MIDDLEWARE
// router.get('/dashboard',(req,res,next)=> {
// res.render('dashboard');
// });
router.get('/dashboard',checkAuth,(req,res,next)=> {
res.render('dashboard');
});
checkAuth is my middleware and idk why it always returns false.
This is passport and session configs in app.js :
//sessions
app.use(session({
secret: 'secret',
saveUninitialized: true,
resave: true,
cookie: { secure: false } // Remember to set this
}));
//passport
app.use(passport.initialize());
app.use(passport.session());
Is there anything wrong with my checkAuth middleware ?
Or my redirect to Dashboard view?
Thanks in advance!
When you call passport.authenticate() method, it uses a strategy to authenticate the user. If you have the user information stored in a local DB, then you can use the Local Strategy that will use username and password to authenticate. So in your app.js add the following:
const LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
/* Change this to fetch user info from your db
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!comparePasswords(user.password, password)) { return done(null, false); }
return done(null, user);
});
*/
}
));
When the user is authenticated, serializeUser() method is called with the user object returned from the above method passed as an argument and express appends the value returned to the current user session in req.session.passport.user
passport.serializeUser(function(user, done) {
done(null, user.id);
});
On each subsequent request, when isAuthenticated() method is called, passport checks if some value is present in req.session.passport.user. If user information is present, it calls the deserializeUser() method which appends the user information to the request and can be accessed via req.user
passport.deserializeUser(function(id, done) {
// Replace it with your db
User.findById(id, function (err, user) {
done(err, user);
});
});

Check if user exists in passport-local

I have an Express app with the passport-local strategy, using Mongoose for storing user Accounts. I had a freelancer write this part of the app for me because I couldn't make sense of how to build the login system from beginning to end (every single tutorial I found did it in a different way). The drawback of this is that I don't understand what each part does. This is in my app.js file:
const Account = require('./models/db/AccountsSchema');
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(Account.authenticate()));
passport.serializeUser(Account.serializeUser());
passport.deserializeUser(Account.deserializeUser());
and this is in routes/index.js:
router.post('/register', function(req, res) {
Account.register(new Account({
username: req.body.username,
name: req.body.name
}), req.body.password, function(err, account) {
if (err) {
console.log(err);
} else {
console.log(account);
passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login'
})(req, res, function(err, user) {
res.redirect('/');
});
}
});
});
along with:
router.post('/login',
passport.authenticate('local'),
function(req, res) {
res.redirect('/');
}
);
Now in the login POST request I want to have a check for whether a user with that particular username exists, so that if the password is wrong at least I can tell the user that the password is wrong. User enumeration is not a security concern here.
Where in my code can I incorporate a database check for whether an Account with the specified username exists?
In Account.authenticate() function. As it sets the LocalStrategy in your case.
setting your local strategy:
passport.use(new LocalStrategy(Account.authenticate()));
Sample Code:
function authenticate(username, password, done) {
User.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}

node js express4 and passport js lengthy sign in

I am using express 4 with passport js to handle authentication of users.
The front end is Angular JS.
I am basically facing two problems:
1- sign in is lengthy, it takes up to 15 seconds to sign in.
2- once logged in, if i restart the node js server and refresh the page I am back to the signin page even though a cookie is set in the browser.
This is what i have in the backend
passport.serializeUser(function (user, done) {
done(null, user._id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
user.password = undefined;
done(err, user);
});
});
passport.use(new LocalStrategy(function (username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, { message: messages['116']});
}
user.comparePassword(password, function (err, isMatch) {
if (err) {
return done(err);
}
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: messages['116']});
}
});
});
}));
app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(express.static(path.join(__dirname, 'public')));
app.use(cookieParser('a very hard to guess string'));
app.use(session({
secret: 'a very hard to guess string'
}
));
app.use(passport.initialize());
app.use(passport.session());
The following is the login route:
router.post('/signin', function (req, res, next) {
var result = _.cloneDeep(SwissArmyKnife.resultObjSkel);
var username = req.body.username;
var password = req.body.password;
if (_.isEmpty(username)) {
result.error.reasons.push(SwissArmyKnife.messages['118']);
}
if (_.isEmpty(password)) {
result.error.reasons.push(SwissArmyKnife.messages['119']);
}
if (!_.isEmpty(result.error.reasons)) {
return res.json(200, result);
}
passport.authenticate('local', function (err, user, info) {
if (err) {
return next(err);
}
if (user) {
req.login(user, function (err) {
if (err) {
return next(err);
}
result.result = true;
return res.json(200, result);
})
}
if (info) {
result.error.reasons.push(info.message);
return res.json(200, result);
}
})(req, res, next);
});
when debugging the above code i notice a huge delay when the code reaches
passport.authenticate('local', function (err, user, info) {
what could be the problem???
what am i doing wrong?
Thanks in advance.
The reason you're seeing the sign-in page after restarting your server is because you are using the memory store for your sessions. As you've noticed this only has so much usefulness and you should use some persistent store instead (e.g. redis).

Trying to use node.js and passport, but authentication page just times out

I'm using passport to do a local authentication. It's pretty simple right now, just a simple login form and login route. It works perfectly when running on my mac, but when I upload it to a rackspace server and try it, I get a timeout when trying to submit the form to /login.
Relevant code (let me know if i need to add more):
//Passport SETUP
passport.serializeUser(function (user, done) {
console.log("serialized");
done(null, user.username);
});
passport.deserializeUser(function (username, done) {
console.log("deserialized");
user = users.getUserByUsername(username);
done(null, user);
});
passport.use(new LocalStrategy(
function (username, password, done) {
users.loginUser(username, password, function(err, user) {
if (err) { return done(err); }
if (user) {
return done(null, user);
} else {
return done(null, false, { message: 'Incorrect Login.'});
}
});
}
));
//middleware
var loginRequired = function(req, res, next){
if (req.isAuthenticated()) { return next(); }
res.redirect('/');
};
//using passport
app.post('/login',
passport.authenticate('local', { successRedirect: '/game',
failureRedirect: '/',
failureFlash: true })
);
//page that i want to eventually get to
app.get('/game', loginRequired, function(req, res){
res.render('game', {title:"Game Page"});
});
note - the deserialize right now is just a cheater that returns the user object, eventually it'll be a callback and all that :).
:( after throwing in console.logs everywhere I found out that it was mysql. The user wasn't created on the server. Not sure why mysql-simple-pool didn't error out, but it didn't.

Passport.js - Error: failed to serialize user into session

I got a problem with the Passport.js module and Express.js.
This is my code and I just want to use a hardcoded login for the first try.
I always get the message:
I searched a lot and found some posts in stackoverflow but I didnt get the failure.
Error: failed to serialize user into session
at pass (c:\Development\private\aortmann\bootstrap_blog\node_modules\passport\lib\passport\index.js:275:19)
My code looks like this.
'use strict';
var express = require('express');
var path = require('path');
var fs = require('fs');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var nodemailer = require('nodemailer');
var app = express();
module.exports = function setupBlog(mailTransport, database){
var config = JSON.parse(fs.readFileSync('./blog.config'));
app.set('view options', {layout: false});
app.use(express.static(path.join(__dirname, '../', 'resources', 'html')));
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({ secret: 'secret' }));
app.use(passport.initialize());
app.use(passport.session());
app.get('/blog/:blogTitle', function(req, res) {
var blogTitle = req.params.blogTitle;
if(blogTitle === 'newest'){
database.getLatestBlogPost(function(post) {
res.send(post);
});
} else {
database.getBlogPostByTitle(blogTitle, function(blogPost) {
res.send(blogPost);
});
}
});
passport.use(new LocalStrategy(function(username, password, done) {
// database.login(username, password, done);
if (username === 'admin' && password === 'admin') {
console.log('in');
done(null, { username: username });
} else {
done(null, false);
}
}));
app.post('/login', passport.authenticate('local', {
successRedirect: '/accessed',
failureRedirect: '/access'
}));
app.listen(8080);
console.log('Blog is running on port 8080');
}();
Thanks.
It looks like you didn't implement passport.serializeUser and passport.deserializeUser. Try adding this:
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
If you decide not to use sessions, you could set the session to false
app.post('/login', passport.authenticate('local', {
successRedirect: '/accessed',
failureRedirect: '/access',
session: false
}));
Sounds like you missed a part of the passportjs setup, specifically these two methods:
passport.serializeUser(function(user, done) {
done(null, user._id);
// if you use Model.id as your idAttribute maybe you'd want
// done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
I added the bit about ._id vs. .id but this snippet is from the Configure Section of docs, give that another read and good luck :)
Here an working but still lazy way to use sessions and still "serialisize" the values.
var user_cache = {};
passport.serializeUser(function(user, next) {
let id = user._id;
user_cache[id] = user;
next(null, id);
});
passport.deserializeUser(function(id, next) {
next(null, user_cache[id]);
});
in case or weird errors just ask yourself: "Do I rlly set '_id' in my user object?" - in most cases you dont. So use a proper attribute as key.
Make sure you have used async and await when getting user data.
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
const USER = await User.findById(id);
done(null, USER);
});
passport.use(
new GoogleStrategy(
{
// options for google strategy
clientID: keys.google.clientID,
clientSecret: keys.google.clientSecret,
callbackURL: "/auth/google/redirect",
},
async (accessToken, refreshToken, profile, done) => {
// passport callback function
// check if user already exist in our db
const oldUser = await User.findOne({ googleId: profile.id });
if (oldUser) {
return done(null, oldUser);
} else {
const newUser = await new User({
username: profile.displayName,
googleId: profile.id,
}).save();
return done(null, newUser);
}
}
)
);
use this code into your server.js file where u can make a get or post request.
app.get('/auth/facebook/callback',passport.authenticate('facebook',{
successRedirect:'/profile',
failureRdirect:'/',
session: false
}))
Using Promise with serializeUser & deserializeUser:
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
// console.log(`id: ${id}`);
User.findById(id)
.then((user) => {
done(null, user);
})
.catch((error) => {
console.log(`Error: ${error}`);
});
});
Please see my github repo for a full code example how to solve this issue.
You missed this code:
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
For details, check the session part in http://www.passportjs.org/docs/configure/
Another prevalent reason for this as I discovered today is that if you are using the standard packages such as passport,passport-local,passport-local-mongoose and express-session and u are already in a session that is you were logging in and then you terminate the server and restart again, you will be in the same session while logging in where the browser keeps loading with no response and you get this error of "failed to serialize user into the session".
Since "user" is returned as an array of objects, try this:
passport.serializeUser(function(user, cb) {
process.nextTick(function() {
return cb(null, user[0].id);
});
});
in passport.use('local-login'...)/ or /('local-singup'...)
if err you have to return "false"
err {return done(null, req.flash('megsign', 'Username already exists #!#'));}
true {return done(null, false, req.flash('megsign', 'Username already exists #!#'));}

Resources