I am trying to use passportjs with the following code.
So when the user goes to http://localhost:3000, he should automatically be redirected to /hello but as it does, it redirects to /hello?failure.
I have tried to debug, look around but haven't found the issue and the solution.
const express = require('express');
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');
let app = express();
app.use(session({
secret: 'mysecret',
cookie: {
secure: false
},
resave: true,
saveUninitialized: true
}
));
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
passport.use('local-login', new LocalStrategy(function (username, password, done) {
console.log(username + ' username ');
console.log(password + ' password ');
return done(null, { name: 'suhail' });
}));
passport.serializeUser(function (user, done) {
console.log(user, ' serialize ');
done(null, user.name);
});
passport.deserializeUser(function (id, done) {
console.log(id, ' deserialize ');
done(null, { name: 'suhail' });
});
app.get('/', passport.authenticate('local-login', { successRedirect: '/hello', failureRedirect: '/hello?failure' }));
app.get('/hello', (req, resp, next) => resp.send('hello').end());
app.listen(3000);
What is it that I am missing? It should go to http://localhost:3000/hello as the middleware always resolves.
Note:
- None of the middleware defined is called. It just redirects to /hello?failure when a GET request to / is made.
You are not providing username and password in your get request. Therefore the Strategycallback is never called.
Try adding this middleware in front of your routing to see what i mean:
app.use((req, res, next) => {
// fake body content for authentication
req.body = {username: 'devil', password: '666'}
next()
})
app.get('/', passport.authenticate('local-login', { successRedirect: '/hello', failureRedirect: '/hello?failure' }));
Related
I am trying to get session data, using passport js. When I use the /test or /test2 route, I get the session data. If I try to console.log in these routes, I get the whole session data. But when I try it with /user_data, I dont seem to get the expected response. Where am I going wrong here? I am using passport.js and express session. When going through the /user_data route, I get the following output:
Session {
cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true }
}
Here is the code I am using, it is fairly dirty as of now as I am trying to tinker around.
const express = require('express')
const app = express()
const session = require('express-session');
const port = 3000
const passport =require("passport")
const GoogleStrategy = require('passport-google-oauth2').Strategy;
const bodyParser = require("body-parser");
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
passport.use(new GoogleStrategy({
clientID:"some.com",
clientSecret:"some_secret",
callbackURL: "http://localhost:3000/auth/google/callback",
passReqToCallback : true
},
function(request, accessToken, refreshToken, profile, done) {
return done(null, profile);
}
));
app.use(session({
resave: false,
saveUninitialized: true,
secret: 'SECRET'
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.get("/failed", (req, res) => {
res.send("Failed")
})
app.get("/success", (req, res) => {
res.send(`Welcome ${req.user.email}`)
})
app.get('/auth/google',
passport.authenticate('google', {
scope:
['email', 'profile']
}
));
app.get('/auth/google/callback',
passport.authenticate('google', {
failureRedirect: '/failed',
}),
function (req, res) {
res.redirect('/')
}
);
app.get("/test",(req,res)=>{
let sess = req.session;
console.log(sess);
var email=sess.passport.user.email;
var netid=email.split('#')[0];
req.session.netid=netid;
console.log(netid);
// console.log(sess.user.id);
res.send("test")
});
app.get("/test2",(req,res)=>{
let sess = req.session;
console.log(sess);
var netid=sess.netid;
console.log(netid);
res.send("test2")
});
app.get("/user_data",(req,res)=>{
var sess = req.session;
console.log(sess.passport);
res.send(sess.passport);
});
app.get('/logout', function(req, res){req.logOut();res.redirect('/');});
app.get('/', (req, res) => {res.sendFile(__dirname + "/pages/index.html");})
app.listen(port, () => console.log(`Example app listening on port ${port}!`))
In theory user_data is just another endpoint and on that basis it should work just like test and test2.
However, user_data could be a reserved name. Try changing that endpoint to something else.
today I was trying to get a passport authentication working. The email and password is static now but I will change that later. I have a lot of debug messages but only the ones outside of the Strategy. No errors or warnings regarding passport are displayed.
I have already tried to use different body parser modes (extented = true, extented = false).
Strategy
const LocalStrategy = require('passport-local').Strategy;
module.exports = function(passport) {
passport.use(
new LocalStrategy((email, password, done) => {
console.log('Authentication started');
var user = null;
if(email == 'test#mytest.com') {
if(password == 'test') {
user = {
email
}
console.log('Authenticated')
return done(null, user);
}
}
console.log('Error')
return done(null, user, {message: 'EMail or Password was wrong'});
})
);
passport.serializeUser(function(user, done) {
done(null, user.email);
});
passport.deserializeUser(function(id, done) {
done(err, user);
});
};
app.js (contains only important parts)
const express = require('express');
const expressSession = require('express-session')
const bodyParser = require('body-parser');
const expressLayouts = require('express-ejs-layouts');
const app = express();
const https = require('https');
const http = require('http');
app.use(expressSession({ secret: 'secret' }));
// Body Parser
app.use(bodyParser.urlencoded({extended:false}));
app.use(bodyParser.json());
// Passport
const passport = require('passport');
require('./config/passport')(passport);
app.use(passport.initialize());
app.use(passport.session());
// View Engine
app.set('view engine', 'ejs');
app.use(expressLayouts);
app.get('/applications', (req,res) => {
res.render('applications', {
user: req.user
});
});
app.post('/applications', (req, res, next) => {
console.log(req.body);
passport.authenticate('local', {
successRedirect: '/applications',
failureRedirect: '/',
failureFlash: false
})(req, res, next);
});
https.createServer(httpsOptions, app)
.listen(7443, () => {
console.log('HTTPS Server started on Port 7443')
});
http.createServer(app)
.listen(7080, () => {
console.log('HTTP Server started on Port 7080')
});
Make sure you are using the proper fields in your POST request. I noticed that in your strategy, you use the variables email and password. While your variable names aren't important, the fields you send in your POST request are. By default, passport-local uses the POST fields username and password. If one of these fields aren't present, the authentication will fail. You can change this to use email instead like so:
passport.use(
new LocalStrategy({
usernameField: 'email'
}, (email, password, done) => {
console.log('Authentication started');
// Your authentication strategy
})
);
Assuming you have the right POST fields, in order to use req.user in requests, you must have properly set up your passport.deserializeUser function. Testing your code, the authentication strategy is working fine for me, however I receive a reference error upon deserializeUser.
Ideally, there is a generic sign in button on the homepage, which redirects to several sign in buttons, one of which is for Facebook. The user clicks that button and, if authenticated, is redirected to /my-reptiles/.
However, what actually happens is that when the user clicks "Log in with Facebook", they are not prompted with a confirmation from Facebook and are immediately redirected back to the homepage from the ensureAuthenticated() method in my-reptiles.js. When running in private browsing, I am asked to log in to Facebook before being redirected, but I am not asked to approve use of Facebook as a login method. Is this normal?
Also a local mongodb entry for the user is still created even though isAuthenticated() fails.
On the Facebook developer console I have app domains set to localhost and site URL set to http://localhost:3000/.
This is the console output:
GET /auth/facebook 302 4.309 ms - 0
GET /auth/facebook/callback?code=LONG_CODE_HERE 302 215.462 ms - 68
Unauthenticated request!
GET /my-reptiles 302 0.879 ms - 46
GET / 304 14.854 ms - -
This is the network log:
my-reptiles.js
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
console.log("Unauthenticated request!");
res.redirect('/');
}
}
router.get('/', ensureAuthenticated, function(req, res, next) {
//Do stuff
});
module.exports = router;
app.js
//Requires here
function findOrCreate(key, cb) {
db.collection('users').findOne(key, (err, user) => {
if (err) {
console.error(err);
} else {
if (!user) {
db.collection("users").insert(key, cb)
} else {
cb(err, user);
}
db.close();
}
});
}
// config
passport.use(new FacebookStrategy(
{
clientID: config.facebook.clientID,
clientSecret: config.facebook.clientSecret,
callbackURL: config.facebook.callbackURL
},
function(accessToken, refreshToken, profile, done) {
findOrCreate({
auth: "facebook",
id: profile.id
}, function (err, user) {
return done(err, user);
});
}
));
var app = express();
//View engine setup here
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({
extended: false
}));
app.use(cookieParser('sekret'));
app.use(express.static(path.join(__dirname, 'public')));
//Routes here
const cookieExpirationDate = new Date();
const cookieExpirationDays = 365;
cookieExpirationDate.setDate(cookieExpirationDate.getDate() + cookieExpirationDays);
app.use(session({
secret: 'sekret',
saveUninitialized: true,
resave: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.get('/auth/facebook', passport.authenticate('facebook'));
app.get('/auth/facebook/callback',
passport.authenticate('facebook', {
successRedirect: '/my-reptiles',
failureRedirect: '/'
})
);
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
//Error handling here
module.exports = app;
The problem was that I was adding session and passport after my routes, when it should have been before them, as per this answer.
//Routes WERE here
const cookieExpirationDate = new Date();
const cookieExpirationDays = 365;
cookieExpirationDate.setDate(cookieExpirationDate.getDate() + cookieExpirationDays);
app.use(session({
secret: 'sekret',
saveUninitialized: true,
resave: true
}));
app.use(passport.initialize());
app.use(passport.session());
//Routes SHOULD BE here
I am trying to integrate passport into my node.js app.
app.js file
const app = express();
app.set('view engine', 'pug');
app.use('/libs', express.static('node_modules'));
require('../config/auth.config')(app, data, passport);
app.use((req, res, next) => {
res.locals.user = req.user;
next();
});
app.get('/', (req, res) => {
// those objects are populated correctly after redirect from auth middleware
console.log(req.session)
console.log(req.user)
return res.render('home');
});
app.get('/login', console.log(req.user);
// req.user is undefined here
if (req.user) {
return res.redirect('/');
}
return res.render('login'););
app.post('/login', passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
}));
auth.config.js
const express = require('express');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const LocalStrategy = require('passport-local');
const MongoStore = require('connect-mongo')(session);
const config = require('./config');
const configAuth = (app, {
users
}, passport, db) => {
app.use(cookieParser('Purple Unicorn'));
app.use(bodyParser.urlencoded({
extended: true,
}));
app.use(bodyParser.json());
app.use(session({
store: new MongoStore({
url: config.connectionString
}),
secret: 'Purple Unicorn',
resave: true,
saveUninitialized: true,
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy((username, password, done) => {
return users.login(username, password)
.then((user) => {
if (user) {
return done(null, user);
}
return done(null, false);
});
}));
passport.serializeUser((user, done) => {
done(null, user._id);
});
passport.deserializeUser((id, done) => {
users.getUserById(id)
.then((user) => {
console.log(user);
if (user) {
done(null, user);
}
done(null, false);
});
});
app.use((req, res, next) => {
res.locals = {
user: req.user,
};
next();
});
};
module.exports = configAuth;
The data object is working correctly.
After the post request on /login with correct data, I am redirected to / where console.log(req.user) prints the correct user. It is also added in the req.session object.
After I follow a link to /login, it should redirect me after the check for req.user but returns undefined. Sessions in mongo are stored correctly.
It seems passport is not saving the session correctly.
The problem is in your deserializeUser method where you always run done callback twice. In if statement you should use return done(null, user); to get out from function;
I'm encountering a little problem when using passport.js with express 4.11.1
Below is my app.js
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
if(username == '1' && password == '1') {
var user = {username: 'test',id: 123,firstName: 'test'};
return done(null, user);
} else {
return done(null, false, {message: 'Incorrect username or password'});
}
}
));
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(username, done) {
var user = {
username: 'test',
id: 123,
firstName: 'test'
};
done(null, user);
});
module.exports = passport;
Then I modified my app.js, adding the middleware
var passport = require('./auth');
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true,
cookie: { secure: true }
}));
app.use(express.static(path.join(__dirname, 'public')));
app.use(passport.initialize());
app.use(passport.session());
At last, I defined in the router:
var passport = require('../auth');
router.get('/login', function (req, res, next) {
res.render('login', {title: 'Login', message: ''});
});
router.post('/login',
passport.authenticate('local',
{
successRedirect: '/user2',
failureRedirect: '/login'
}));
router.get('/user2', function(req, res) {
console.log(req.session.passport);
if(req.session.passport.user === undefined) {
res.redirect('/login');
} else {
res.render('user2', {title: 'Welcome!', user: req.user});
}
});
Now the problem that I found is that I can successfully login, however when I try to print out req.session.passport, I found the passport object in session is {}. I guess maybe it's because the passport.serializeUser function doesn't really work, but when I try printing out the user object passed to the passport.serializeUser function, it has values. Can someone help me look into this issue? Thanks in advance.
Your code looks fine, except this part:
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true,
cookie: { secure: true } <<<<<<<<<<
}));
docs say that you should use secure cookies when you are using https, so excluding this field should fix your problem.
secure boolean marks the cookie to be used with HTTPS only.