Related
I'm building an app in Node, using Passport and local signup and sign in strategies. I just keep running into an issue. All the required modules etc. are there. The following sign in routine works fine:
passport.use('local-signin', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqTodone : true
}, function(req, email, password, done) {
User.findOne({ 'local.email' : email }, function(err, user) {
if (err)
return done(err);
if (!user)
return done(null, false, req.flash('message', 'User not found.'));
if (!user.validPassword(password))
return done(null, false, req.flash('message', 'Wrong password.'));
return done(null, user);
});
}));
However, the following sign up routine does not:
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqTodone : true
}, function(req, email, password, done) {
console.log("signing up")
User.findOne({ 'local.email' : email }, function(err, user) {
if (err) {
return done(err);
} else if (user) {
return done(null, false, req.flash('message', 'That email address is already registered.'));
} else {
var newUser = new User();
}
// save the user
newUser.save(function(err) {
if (err) {
console.log("Error saving new user profile: " + err);
} else {
return done(null, newUser, req.flash('message', 'User account created'));
}
});
});
}))
Both routines are called within routes.js:
// POST : SIGNUP
app.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/',
failureRedirect: '/error',
failureFlash: true
}));
// POST : SIGNIN
app.post('/signin', passport.authenticate('local-signin', {
successRedirect: '/profile',
failureRedirect: '/',
failureFlash: true
}));
Any ideas where it might go wrong? As is, posting to /signup continuously results in a failureRedirect. My head is getting kinda sore from banging on the screen...
The only thing you need to change is:
if (!user.validPassword(password))
To
if (user.validPassword(password) === false)
I know, if (!user.validPassword(password)) is in examples on Passport.js official docs, but it is wrong.
I have just lost 2 hours of my life, figuring this out.
Use this code it will helps you to fix your problem
passport-authentication.js
var express=require('express');
var router = express.Router();
var passport = require('passport');
var User = require('../models/user');//user is schema
var Verify = require('./verify');//verify is a file where the user is verified
/* GET users listing. */
router.get('/', Verify.verifyOrdinaryUser,function(req, res, next) {
User.find({},function(err,user){
if(err) throw err;
res.json(user);
});
});
router.post('/register', function(req, res) {
User.register(new User({ username : req.body.username,Email:req.body.Email}),
req.body.password, function(err, user) {
if (err) {
return res.status(500).json({err: err});
}
if(req.body.firstname) {
user.firstname = req.body.firstname;
}
if(req.body.lastname) {
user.lastname = req.body.lastname;
}
user.save(function(err,user) {
passport.authenticate('local')(req, res, function () {
return res.status(200).json({status: 'Registration Successful!'});
});
});
});
});
router.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json({
err: info
});
}
req.logIn(user, function(err) {
if (err) {
return res.status(500).json({
err: 'Could not log in user'
});
}
var token = Verify.getToken(user);
res.status(200).json({
status: 'Login successful!',
success: true,
token: token
});
});
})(req,res,next);
});
router.get('/logout', function(req, res) {
req.logout();
res.status(200).json({
status: 'Bye!'
});
});
module.exports = router;
verify.js
var User = require('../models/user');
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var config = require('../config.js');
exports.getToken = function (user) {
return jwt.sign(user, config.secretKey, {
expiresIn: 3600
});
};
exports.verifyOrdinaryUser = function (req, res, next) {
// check header or url parameters or post parameters for token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// verifies secret and checks exp
jwt.verify(token, config.secretKey, function (err, decoded) {
if (err) {
var err = new Error('You are not authenticated!');
err.status = 401;
return next(err);
} else {
// if everything is good, save to request for use in other routes
req.decoded = decoded;
next();
}
});
} else {
// if there is no token
// return an error
var err = new Error('No token provided!');
err.status = 403;
return next(err);
}
};
hope this helps for you...
I am currently implementing a Google login and Google calendar implementation and testing out a function when a Google user logs in it pulls their events and prints to the console. however, I am getting the following error in the console
Error: Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.
and when I console.log the calendar, it gives me a null.
I have made sure Google+ API and Google calendar API are both enabled in the console as well.
I am new to web development in general, I followed a tutorial to get me started and began trying to use the Google API's. I am using the MEAN stack for this project. Here is the relevant code.
var FacebookStrategy = require('passport-facebook').Strategy;
var User = require('../models/user');
var session = require('express-session');
var jwt = require('jsonwebtoken');
var secret = 'check123';
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
var gcal = require('google-calendar');
var google = require('googleapis');
module.exports = function(app,passport, auth) {
app.use(passport.initialize());
app.use(passport.session());
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: false }
}));
passport.serializeUser(function(user, done) {
token = jwt.sign({ username: user.username, email: user.email }, secret, {expiresIn: '24h'});
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use(new FacebookStrategy({
clientID: '422080801499546',
clientSecret: '34f91021248106dea49daa111bb7ff89',
callbackURL: "http://localhost:8000/auth/facebook/callback",
profileFields: ['id', 'displayName', 'photos', 'email']
},
function(accessToken, refreshToken, profile, done) {
console.log(profile._json.email);
User.findOne({ email: profile._json.email }).select('username password email').exec(function(err, user){
if(err) done(err);
if (user && user !== null) {
done(null, user);
} else {
done(err);
}
});
//done(null, profile);
}
));
// Use the GoogleStrategy within Passport.
// Strategies in Passport require a `verify` function, which accept
// credentials (in this case, an accessToken, refreshToken, and Google
// profile), and invoke a callback with a user object.
passport.use(new GoogleStrategy({
clientID: '655984940226-ob15jvq3hvqha4969tlb3oco9tun1i9t.apps.googleusercontent.com',
clientSecret: 'hsZtBDsfiCvdPz0gT-tqdUZ_',
callbackURL: "https://frozen-woodland-75947.herokuapp.com/auth/google/callback"
},
function(accessToken, refreshToken, profile, done) {
User.findOne({ email: profile.emails[0].value }).select('username password email').exec(function(err, user){
if(err) done(err);
if (user && user !== null) {
done(null, user);
} else {
done(err);
}
});
var google_calendar = google.calendar('v3');
console.log('im here');
google_calendar.events.list({
auth: auth,
calendarId: 'primary',
timeMin: (new Date()).toISOString(),
singleEvents: true,
orderBy: 'startTime'
}, function(err, calendarList){
console.log(calendarList);
if(err){
console.log('bad list: ' + err);
return;
}
var events = calendarList.items;
if(events.length ==0){
console.log('No items found');
} else {
console.log('Upcoming events:');
console.log('%s -%s', start, event.summary);
}
})
}
Next is my authentication functions, my api.js:
var User = require('../models/user');
var jwt = require('jsonwebtoken');
var secret = 'check123';
module.exports = function(router){
//USER REGISTRATION
router.post('/users', function(req, res){
var user = new User();
user.username = req.body.username;
user.password = req.body.password;
user.email = req.body.email;
if(req.body.username == null || req.body.username == ''|| req.body.password == null || req.body.email == null || req.body.password == '' || req.body.email == ''){
res.json({ success: false, message: 'Ensure username, email, and password were provided'}); //false if the route is null empty etc.
} else {
user.save(function(err){
if(err) {
res.json({success: false, message: 'Username or email already exists'});
} else {
res.json({success: true, message: 'user created!'});
}
});
}
});
//USER LOGIN ROUTE
//http://localhost:port/api/authenticate
router.post('/authenticate', function(req,res){
User.findOne({ username: req.body.username }).select('email username password').exec(function(err,user){
if(err) throw err;
if(!user){
res.json({success: false, message: 'Could not authenticate user'});
} else if (user) {
if( req.body.password) {
var validPassword = user.comparePassword(req.body.password);
} else {
res.json({success: false, message: 'No password Provided'});
}
if(!validPassword) {
res.json({ success: false, message: ' Could not Authenticate password'});
} else {
var token = jwt.sign({ username: user.username, email: user.email }, secret, {expiresIn: '24h'}); // create json token when they successfully log in with secret encryption and expires in 24 hours
res.json({ success: true, message: ' User Authenticated!', token: token}); // respond to user with that token
}
}
});
});
router.use(function(req, res, next){
var token = req.body.token || req.body.query || req.headers['x-access-token'];
console.log(token);
if(token) {
//varify token
jwt.verify(token,secret,function(err,decoded){
if(err) {
res.json({success: false, message: 'Token invalid'});
} else {
req.decoded = decoded; //decrpyts token - user/email
next();
}
});
}else {
res.json({success: false, message: 'No token provided'});
}
});
router.post('/me', function(req, res) {
res.send(req.decoded);
});
return router;
}
Login controllers:
//controls main index - runs when main page loads
angular.module('mainController', ['authServices'])
.controller('mainCtrl', function(Auth,$timeout, $location,$rootScope, $window){
var app = this; // so we can access outside of scoper
app.loadme = false;
$rootScope.$on('$routeChangeStart', function() {
if(Auth.isLoggedIn()) {
app.isLoggedIn = true;
Auth.getUser().then(function(data){
app.username = data.data.username;
app.useremail = data.data.email;
app.loadme = true;
});
} else {
app.isLoggedIn = false;
app.username = '';
app.loadme = true;
}
});
this.google = function() {
$window.location = $window.location.protocol + '//' + $window.location.host + '/auth/google';
};
this.doLogin = function(loginData) { //when the register button is pressed controller
app.loading = true;
app.errorMsg = false;
Auth.login(app.loginData).then(function(data){
if(data.data.success){
app.loading = false;
app.successMsg = data.data.message + '...redirecting';
$timeout(function() {
$location.path('/about');
app.loginData = '';
app.successMsg = false;
}, 2000);
} else {
app.loading = false;
app.errorMsg = data.data.message;
}
});
};
this.logout = function() {
Auth.logout();
$location.path('/logout');
$timeout(function(){
$location.path('/');
}, 2000);
};
})
I know variations of this questions have been asked multiple times. My understanding is that you basically have to watch your if/else logic and make sure that done isn't being called multiple times.
Twitter and Google work fine. Facebook is giving me this error though:
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
at ServerResponse.header (/Users/azerner/code/mean-starter/node_modules/express/lib/response.js:718:10)
at ServerResponse.location (/Users/azerner/code/mean-starter/node_modules/express/lib/response.js:835:8)
at ServerResponse.redirect (/Users/azerner/code/mean-starter/node_modules/express/lib/response.js:874:8)
at complete (/Users/azerner/code/mean-starter/node_modules/passport/lib/middleware/authenticate.js:241:26)
at /Users/azerner/code/mean-starter/node_modules/passport/lib/middleware/authenticate.js:250:15
at pass (/Users/azerner/code/mean-starter/node_modules/passport/lib/authenticator.js:427:14)
at Authenticator.transformAuthInfo (/Users/azerner/code/mean-starter/node_modules/passport/lib/authenticator.js:449:5)
at /Users/azerner/code/mean-starter/node_modules/passport/lib/middleware/authenticate.js:247:22
at /Users/azerner/code/mean-starter/node_modules/passport/lib/http/request.js:51:7
at pass (/Users/azerner/code/mean-starter/node_modules/passport/lib/authenticator.js:273:43)
at serialized (/Users/azerner/code/mean-starter/node_modules/passport/lib/authenticator.js:282:7)
at /Users/azerner/code/mean-starter/server/passport.js:17:5
at pass (/Users/azerner/code/mean-starter/node_modules/passport/lib/authenticator.js:290:9)
at Authenticator.serializeUser (/Users/azerner/code/mean-starter/node_modules/passport/lib/authenticator.js:295:5)
at IncomingMessage.req.login.req.logIn (/Users/azerner/code/mean-starter/node_modules/passport/lib/http/request.js:48:29)
passport.js
var LocalStrategy = require('passport-local').Strategy;
var FacebookStrategy = require('passport-facebook').Strategy;
var TwitterStrategy = require('passport-twitter').Strategy;
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
var mongoose = require('mongoose');
var User = mongoose.model('User');
var Local = mongoose.model('Local');
var Facebook = mongoose.model('Facebook');
var Twitter = mongoose.model('Twitter');
var Google = mongoose.model('Google');
var bcrypt = require('bcrypt');
var config = require('./config.json');
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
User
.findById(id).populate('local').exec()
.then(function(user) {
console.log('deserializeUser found user: ', user);
done(null, user);
}, done)
;
});
// LOCAL
passport.use(new LocalStrategy(function(username, password, done) {
Local
.findOne({ username: username })
.select('username role hashedPassword')
.exec()
.then(function(local) {
if (!local) {
return done(null, false);
}
var validPassword = bcrypt.compareSync(password, local.hashedPassword);
if (!validPassword) {
return done(null, false);
}
else {
User
.findOne({ local: local })
.populate('local')
.exec()
.then(function(user) {
return done(null, user);
})
;
}
})
;
}));
// FACEBOOK
passport.use(new FacebookStrategy({
clientID: config.facebookAuth.clientID,
clientSecret: config.facebookAuth.clientSecret,
callbackURL: config.facebookAuth.callbackURL
}, function(token, refreshToken, profile, done) {
// asynchronous
process.nextTick(function() {
Facebook
.findOne({ id: profile.id })
.select('id token')
.exec()
.then(function(facebook) {
if (facebook) {
User
.findOne({ facebook: facebook._id }).exec()
.then(function(user) {
return done(null, user);
})
;
}
else {
Facebook
.create({ id: profile.id, token: token })
.then(function(createdFacebook) {
User
.create({ facebook: createdFacebook })
.then(function(user) {
return done(null, user);
})
;
})
;
}
})
.then(function(err) {
return done(err);
})
;
});
}));
// TWITTER
passport.use(new TwitterStrategy({
consumerKey: config.twitterAuth.consumerKey,
consumerSecret: config.twitterAuth.consumerSecret,
callbackURL: config.twitterAuth.callbackURL
}, function(token, tokenSecret, profile, done) {
process.nextTick(function() {
Twitter
.findOne({ id: profile.id })
.select('id token')
.exec()
.then(function(twitter) {
if (twitter) {
User
.findOne({ twitter: twitter._id }).exec()
.then(function(user) {
return done(null, user);
})
;
}
else {
Twitter
.create({ id: profile.id, token: token })
.then(function(createdTwitter) {
User
.create({ twitter: createdTwitter })
.then(function(user) {
return done(null, user);
})
;
})
;
}
})
.then(null, function(err) {
return done(err);
})
;
});
}));
// GOOGLE
passport.use(new GoogleStrategy({
clientID: config.googleAuth.clientID,
clientSecret: config.googleAuth.clientSecret,
callbackURL: config.googleAuth.callbackURL
}, function(token, refreshToken, profile, done) {
process.nextTick(function() {
Google
.findOne({ id: profile.id })
.select('id token')
.exec()
.then(function(google) {
if (google) {
User
.findOne({ google: google._id }).exec()
.then(function(user) {
return done(null, user);
})
;
}
else {
Google
.create({ id: profile.id, token: token })
.then(function(createdGoogle) {
User
.create({ google: createdGoogle })
.then(function(user) {
return done(null, user);
})
;
})
;
}
})
.then(null, function(err) {
return done(err);
})
;
});
}));
};
auth.routes.js
var mongoose = require('mongoose');
var express = require('express');
var passport = require('passport');
var Auth = require('./auth.service.js');
try {
var User = mongoose.model('User');
}
catch(e) {
var User = mongoose.model('User', require('../users/user.model.js').UserSchema);
}
var router = express.Router();
// LOCAL
router.post('/login', passport.authenticate('local'), function(req, res) {
res.status(200).json(req.user);
});
router.get('/logout', Auth.isLoggedIn, function(req, res) {
req.logout();
res.status(204).end();
});
router.get('/current-user', Auth.isLoggedIn, function(req, res) {
res.status(200).json(req.user);
});
// FACEBOOK
router.get('/auth/facebook', passport.authenticate('facebook'));
router.get('/auth/facebook/callback',
passport.authenticate('facebook', {
successRedirect: '/',
failureRedirect: '/login'
})
);
// TWITTER
router.get('/auth/twitter', passport.authenticate('twitter'));
router.get('/auth/twitter/callback',
passport.authenticate('twitter', {
successRedirect: '/',
failureRedirect: '/login'
})
);
// GOOGLE
router.get('/auth/google', passport.authenticate('google', { scope: ['profile'] }));
router.get('/auth/google/callback',
passport.authenticate('google', {
successRedirect: '/',
failureRedirect: '/login'
})
);
module.exports = router;
It's also worth noting that I have been using this to block Facebook, but I unblocked it to work on this. I did the commands, force quit Chrome and reopened it, and now I can log into facebook.com fine.
Edit: Oh, and I checked MongoHub and it shows that the User (and Facebook subdocument) have been created.
I'm trying to test my local-login. I've implemented with passport.js, following its guide and following this MEAN skeleton.
I'm pretty sure that the implementation is fine, but there is something wrong with the test that always fails authentication.
If authentication fails it should be redirect to "/signin"if authentication is correct it should be go to "/"
But when I test, the authentication always fails.
This is routes.js:
module.exports = function(app, passport, auth) {
var users = require('../app/controllers/users');
app.get('/signin', users.signin);
app.post('/users/session', passport.authenticate('local', {
failureRedirect: '/signin',
failureFlash: 'Invalid email or password.'
}), users.session);
var index = require('../app/controllers/index');
app.get('/', index.render);
passport.js:
var mongoose = require('mongoose'),
LocalStrategy = require('passport-local').Strategy,
User = mongoose.model('User'),
config = require('./config');
module.exports = function(passport) {
//Serialize sessions
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findOne({
_id: id
}, '-salt -hashed_password', function(err, user) {
done(err, user);
});
});
//Use local strategy
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
function(email, password, done) {
User.findOne({
email: email
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {
message: 'Unknown user'
});
}
if (!user.authenticate(password)) {
return done(null, false, {
message: 'Invalid password'
});
}
return done(null, user);
});
}
));
}
and test: api.js:
var User, app, mongoose, request, server, should, user;
should = require("should");
app = require("../server");
mongoose = require("mongoose");
User = mongoose.model("User");
request = require("supertest");
server = request.agent("http://localhost:3000");
describe("<Unit Test>", function() {
return describe("API User:", function() {
before(function(done) {
user = new User({
email : "user#user.com",
firstName: "Full Name",
lastName : "Last Name",
password : "pass11"
});
user.save();
return done();
});
describe("Authentication", function() {
return it("Local login", function(done) {
return server.post("/users/session").send({
email : "user#user.com",
password: "pass11"
}).end(function(err, res) {
res.headers.location.should.have.equal("/");
return done();
});
});
});
return after(function(done) {
User.remove().exec();
return done();
});
});
});
This is what the terminal displays:
<Unit Test>
API User:
Authentication
1) Local login
0 passing (24ms)
1 failing
1) <Unit Test> API User: Authentication Local login:
actual expected
/signin
I'm trying using this code and work as expected
var User, app, mongoose, request, server, should, user, agent;
should = require("should");
app = require("../server");
mongoose = require("mongoose");
User = mongoose.model("User");
request = require("supertest");
agent = request.agent(app)
describe('User', function () {
before(function(done) {
user = new User({
email : "user#user.com",
firstName: "Full Name",
lastName : "Last Name",
password : "pass11"
});
user.save(done)
});
describe('Login test', function () {
it('should redirect to /', function (done) {
agent
.post('/users/session')
.field('email', 'user#user.com')
.field('password', 'pass11')
.expect('Location','/')
.end(done)
})
after(function(done) {
User.remove().exec();
return done();
});
})
})
for more reference check this test-user
here my screenshot
I am using passportjs for facebook authentication. Here is my facebook strategy:
passport.use(new FacebookStrategy({
clientID: config.facebook.clientID,
clientSecret: config.facebook.clientSecret,
callbackURL: config.facebook.callbackURL
}, function(accessToken, refreshToken, profile, done) {
User.findOne({ 'facebook.id': profile.id }, function (err, user) {
if (err) { return done(err); }
if (!user) {
user = new User({
name: profile.displayName,
email: profile.emails[0].value,
username: profile.username,
provider: 'facebook',
facebook: profile._json
});
user.save(function (err) {
if (err) {
console.log(err);
}
return done(err, user);
});
} else {
return done(err, user);
}
});
}));
I added the following routes:
app.get('/facebook/auth', passport.authenticate('facebook', { scope: [ 'email', 'user_about_me', 'publish_actions']}), function(req, res) { });
// I need the following fix due to this: http://stackoverflow.com/a/17015836/289246
app.get('/facebook/auth/callback', function(req, res, next) {
if (req.query && !req.query.error && req.query.error_code) {
req.query.error = true;
}
next();
},
passport.authenticate('facebook', { failureRedirect: '/facebook-auth-failure', successRedirect: '/auth-success', failureFlash: true })
);
app.get('/facebook-auth-failure', users.authFailure);
app.get('/auth-success', users.authSuccess);
My users.authFailure method is:
exports.authFailure = function (req, res) {
var error = ???
// How can I get here the error message??
res.render('auth-failure', {
error: error || 'An error has accured'
});
};
In case of facebook authentication failure, how can I get the error message (I want to display it to the user)?
Since you're using failureFlash, this should do it:
var error = req.flash('error');
I experienced many many problems and bugs and configurations issues during working with Passport. My solution was to move to Everyauth.
I don't know if this will be any use to you but I got access to flash messages this way.
When you are defining the FacebookStrategy use the passReqToCallback parameter.
passport.use(new FacebookStrategy({
clientID: facebook.getClientID(),
clientSecret: facebook.getClientSecret(),
callbackURL: facebook.getCallback(),
passReqToCallback: true
this will allow you to add the req.flash() as a parameter to the done() like so
return done(false, user, reg.flash('success', 'Sign in successfull'));
Hope that sheds some light on the situation for you or anybody else looking for help