passport login authentication without password field - node.js

I am building user registration using nodejs and express. I am creating a new user without any passport or any authentication strategy. what I want is user should be treated as logged in once he registered successfully.
So I am building login api for user. Where user can authentic using only email field (as I am not storing any password with user). But I am not able to validate user as I am getting 'missing credential' in passport authentication.
app.js
var config = require('./config/development');
var passport = require('passport');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var app = express();
//connect db
mongoose.connect(config.db);
mongoose.set('debug', config.mongoose.debug);
require('./config/passport')(passport); // pass passport for configuration
//initialize all models
var modelsPath = require('path').join(__dirname, 'models');
require('fs').readdirSync(modelsPath).forEach(function(file) {
require('./models/' + file);
});
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(expressValidator());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cookieParser());
/// required for passport
app.use(session({
secret: 'anystringoftext',
saveUninitialized: true,
resave: true
})); // session secret
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(express.static(path.join(__dirname, 'public')));
require('./routes')(app, passport);
passport.js
var mongoose = require('mongoose'),
LocalStrategy = require('passport-local').Strategy,
User = require('../models/users');
module.exports = function(passport) {
// Serialize the user id to push into the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// Deserialize the user object based on a pre-serialized token
// which is the user id
passport.deserializeUser(function(id, done) {
User.findOne({
_id: id
}, function(err, user) {
done(err, user);
});
});
// Use local strategy
passport.use(new LocalStrategy({
usernameField: 'email',
passReqToCallback : true
},
function(email, password, done) {
User.findOne({
email: email
}, function(err, user) {
if (err) {
return done(err);
} else {
return done(null, user);
}
});
}
));
return passport;
};
routes/user.js
module.exports = function(app, passport) {
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (user === false) {
res.json('no user found');
} else {
res.json('login successful');
}
})(req, res, next);
});
};
Will anyone please help me to figure out what am I doing wrong here.

You're halfway there. You can use passport-local and have it only require a username field.
You can override the username and password field to use the same key.
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'email',
passReqToCallback : true
},
Then it only requires that you include one field in the login request.

Related

Passport req.user not persisting across requests -

Using passport.js local strategy I am trying to use the req.user to obtain current user id so that I can store recipes in the database with the users id. The problem seems to be around the deserialization part of the passport.js file I have in my config file in my app. Whenever I hit the /api/saveRecipe route for some reason it gets deserialized and the req user is then no longer available.
Notes: I am authenticating on my backend server using react on the front end.
Below is my server.js file
Problem: req.user is available after calling passport.authenticate('local') but once api/saveRecipe route is hit req.user is no longer available.
After researching this subject on S.O. it appears that it most often has to do with order in the server file setup but i have looked and reviewed and i believe my setup correct...
const express = require("express");
const bodyParser = require("body-parser");
const session = require("express-session");
const routes = require("./routes");
// Requiring passport as we've configured it
let passport = require("./config/passport");
const sequelize = require("sequelize");
// const routes = require("./routes");
const app = express();
var db = require("./models");
const PORT = process.env.PORT || 3001;
// Define middleware here
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
// passport stuff
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(express.static("public"));
// We need to use sessions to keep track of our user's login status
// app.use(cookieParser('cookit'));
app.use(
session({
secret: "cookit",
name: "cookit_Cookie"
})
);
app.use(passport.initialize());
app.use(passport.session());
// Serve up static assets (usually on heroku)
if (process.env.NODE_ENV === "production") {
app.use(express.static("client/public"));
}
// the view files are JavaScript files, hence the extension
app.set('view engine', 'js');
// the directory containing the view files
app.set('pages', './');
// Add routes, both API and view
app.use(routes);
// Syncing our database and logging a message to the user upon success
db.connection.sync().then(function() {
console.log("\nDB connected\n")
// Start the API server
app.listen(PORT, function() {
console.log(`🌎 ==> API Server now listening on PORT ${PORT}!`);
});
});
module.exports = app;
my passport.js code
//we import passport packages required for authentication
var passport = require("passport");
var LocalStrategy = require("passport-local").Strategy;
//
//We will need the models folder to check passport against
var db = require("../models");
// Telling passport we want to use a Local Strategy. In other words, we want login with a username/email and password
passport.use(
new LocalStrategy(
// Our user will sign in using an email, rather than a "username"
{
usernameField: "email",
passwordField: "password",
passReqToCallback: true
},
function(req, username, password, done) {
// console.log(`loggin in with email: ${username} \n and password: ${password}`)
// When a user tries to sign in this code runs
db.User.findOne({
where: {
email: username
}
}).then(function(dbUser) {
// console.log(dbUser)
// If there's no user with the given email
if (!dbUser) {
return done(null, false, {
message: "Incorrect email."
});
}
// If there is a user with the given email, but the password the user gives us is incorrect
else if (!dbUser.validPassword(password)) {
return done(null, false, {
message: "Incorrect password."
});
}
// If none of the above, return the user
return done(null, dbUser);
});
}
)
);
// serialize determines what to store in the session data so we are storing email, ID and firstName
passport.serializeUser(function(user, done) {
console.log(`\n\n serializing ${user.id}\n`)
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
console.log(`\n\n DEserializing ${id}\n`)
db.User.findOne({where: {id:id}}, function(err, user) {
done(err, user);
});
});
// Exporting our configured passport
module.exports = passport;
const router = require("express").Router();
const controller = require("../../controllers/controller.js");
const passport = require("../../config/passport");
router.post(
"/login",
passport.authenticate("local", { failureRedirect: "/login" }),
function(req, res) {
console.log(`req body -${req.body}`);
res.json({
message: "user authenticated",
});
}
);
router.post("/saveRecipe", (req, res) => {
console.log(req.user)
if (req.isAuthenticated()) {
controller.saveRecipe;
} else {
res.json({ message: "user not signed in" });
}
});
module.exports = router;
The problem is in your router.post('login'). Try changing it to something like this:
app.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login/failed'})
)
This will correctly set the req.user in your next requests!

Authentication failure with passport middleware never gets invoked

The following program uses passportjs for username/password authentication. I do not what mistake am I making, but I am always redirected to the failure page, i.e back again to the login page.
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy
, express = require('express');
var app = express();
app.listen(3000);
app.use(express.static(__dirname+'/public'));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(
function(username, password, done) {
console.log(username + ':username');
console.log(password + ':password');
return done(null, [{username:'foo'}]);
}
));
app.get('/login',(req,resp) => {
var options = {
root: __dirname + '/public/'
};
resp.sendFile('login.html',options);
});
app.post('/login',
passport.authenticate('local', { successRedirect: '/',failureRedirect: '/login'})
);
I am trying to understand the working of passportjs and I see that the middleware passport.use(new LocalStrategy( never gets invoked. I do not know the reason but may be it could be the root cause of failure.
So I was missing body parser module required by passportjs to parse the post request. Here is the complete code:
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy
, express = require('express')
, bodyParser = require('body-parser');
var app = express();
app.listen(3000);
app.use(express.static(__dirname+'/public'));
app.use(bodyParser.urlencoded({ extended: false }));// parse application/x-www-form-urlencoded
app.use(bodyParser.json()); // parse application/json
app.use(passport.initialize());
app.use(passport.session());
passport.use('local',new LocalStrategy(
function(username, password, done) {
console.log(username + ':username');
console.log(password + ':password');
return done(null, {username:username});
}
));
passport.serializeUser(function(user, done) {
done(null, user.username);
});
passport.deserializeUser(function(id, done) {
done(null, user);
});
app.get('/login',(req,resp) => {
var options = {
root: __dirname + '/public/'
};
resp.sendFile('login.html',options);
});
app.post('/login',
passport.authenticate('local', { successRedirect: '/',failureRedirect: '/login'})
);
Maybe passport need session try add app.use(express.session({ secret: 'keyboard cat' })); before passport config.
You must name your strategy and serialize user
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.use('local', new LocalStrategy(
function(username, password, done) {
console.log(username + ':username');
console.log(password + ':password');
return done(null, [{username:'foo'}]);
}
));
You call this strategy by name in this eg local
app.post('/login',
passport.authenticate('local', { successRedirect: '/',failureRedirect: '/login'})
);

PassportJS: User Is Not Defined

Yes, I see that this question has been asked here and here, but the answers point to either making changes to your deserializeUser callback, or changing something in your Mongoose model.
I've tried the first to no avail and am using the regular ol' NodeJS driver, so I'm not quite sure where to pinpoint the root cause of my issue.
Here's my script:
AUTHENTICATE.JS:
var app = require('express');
var router = app.Router();
var assert = require('assert');
var bcrypt = require('bcrypt');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
function(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);
});
}
));
router.post('/login',
passport.authenticate('local', {successRedirect:'/',
failureRedirect:'/login',failureFlash: false}),
function(req, res) {
res.redirect('/');
});
For my app.js file I've tried a number of the fixes suggested in similar questions but nothing has made a difference. This is what it looks like:
APP.JS:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var expressValidator = require('express-validator');
var passport = require('passport');
var localStrategy = require('passport-local').Strategy;
var mongo = require('mongodb').MongoClient;
var session = require('express-session');
var bcrypt = require('bcrypt');
// Express Session
app.use(session({
secret: 'keyboard cat',
saveUninitialized: true,
resave: true,
cookie: {secure: true}
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
//initialize passport for app
app.use(passport.initialize());
app.use(passport.session());
// make mongodb available to the application
app.use((req, res, next) => {
mongo.connect('mongodb://localhost:27017/formulas', (e, db) => {
if (e) return next(e);
req.db = db;
next();
});
});
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.use(express.static(__dirname + '/public'));
// Express Validator
app.use(expressValidator({
errorFormatter: function(param, msg, value) {
var namespace = param.split('.')
, root = namespace.shift()
, formParam = root;
while(namespace.length) {
formParam += '[' + namespace.shift() + ']';
}
return {
param : formParam,
msg : msg,
value : value
};
}
}));
//define routes here
app.set('port', (process.env.PORT || 3000));
app.listen(app.get('port'), function(){
console.log("The server is now listening on port "+app.get('port'));
});
module.exports = app;
Any help would be greatly appreciated, thank you.
As both questions you included point out, you need to define the User class first before you can use it. It's not something that passportjs or expressjs provide, you need to implement it for yourself or use another module that gives you that functionality (like mongoose).
In the first SO link you shared the answer suggested the OP implement a user model (User) in mongoose (it seems to be a popular choice).
The second links answer simplified things a bit by adding a hard-coded object to represent the user in the deserializer function.

PassportJS not saving session in local strategy

I'm loosely following the tutorial here, and I'm not sure why it's not working. Logging in will work fine -- it accepts and rejects me exactly how I'd expect, it will just not save the session, so visiting any links after will say that I am not authenticated.
Vivaldi dev panel says that no cookies or sessions are saved. I have set it up to save my sessions in redis and user authentication in PostgreSQL, and both databases are connected to fine.
Here is the relevant code:
index.js:
const express = require('express');
const passport = require('passport');
const session = require('express-session');
const Redis = require('ioredis');
const RedisStore = require('connect-redis')(session);
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
const auth = require("./app/authenticate");
const config = require('./config');
const app = express();
var redis_client = new Redis({
host: config.redisStore.host,
port: config.redisStore.port,
lazyConnect: true
});
redis_client.connect().catch(function(err) {
throw err;
});
app.use(cookieParser(config.redisStore.secret));
app.use(session({
cookie : {
maxAge: 36000000000,
secure: true
},
secret: config.redisStore.secret,
store: new RedisStore({ client: redis_client }),
resave: false,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(bodyParser.urlencoded({extended: true}));
auth.init.initPassport();
app.post('/login', passport.authenticate('local', {
successRedirect: '/testroute',
failureRedirect: '/'
}));
var urlencodedParser = bodyParser.urlencoded({extended: false});
app.get("/testroute", passport.authenticationMiddleware(), urlencodedParser, function(req, res) {
res.send("You are authenticated!");
});
app.listen(8080);
/app/authenticate/init.js:
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const scrypt = require("scrypt");
const auth = require("./userfunctions");
const authenticationMiddleware = function() {
return function (req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.send('ERR: You are not authenticated!');
};
}
module.exports = {
initPassport: function() {
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(id, done) {
auth.getUserById(id, done);
});
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'pwd',
},
function(username, password, done) {
auth.login(username, function(err, user) {
if (err) {console.log(err); return done(err);}
if (!user) {return done(null, false);}
if (!scrypt.verifyKdfSync(user.password, password)) {return done(null, false);}
return done(null, user);
});
}
));
passport.authenticationMiddleware = authenticationMiddleware;
}
};
There are a few other files in /app/authenticate, which are index.js (just adds all the other things to modules.exports) and userfunctions.js, which just includes login and signup functions. I can post these if you need.
I have also omitted the config file, which is just database credentials for PostgreSQL and redis. Finally I have excluded test.html which is served when you GET /, and is just a test HTML login and signup form.
You can use express-session npm module to save your session value.
Below are the steps-
npm install express-session
In your startup JS file write below code
var expressSession = require('express-session');
app.use(expressSession({secret: 'yourothersecretcode', saveUninitialized: true, resave: true}));
Now you can use req.session in your code
req.session is just a json object that gets persisted by the express-session middleware, using a store of your choice e.g. Mongo or Redis.

Passport method isAuthenticated() is false even after successful authentication using Google Strategy

I'm new to MEAN stack and I'm trying to setup a simple social login using google passport strategy. I can successfully authenticate myself, but when calling a redirect on success, the middle ware function isLoggedIn keeps showing req.isAuthenticated() to be false. Below are code snippets. I saw that there were multiple posts on this issue but none of the answers seem to work for me. Kindly help me resolve this issue.
passport.js
var Auth = require('./auth.js');
var ubCust = require('../models/ubCust.js');
var FacebookStrategy = require('passport-facebook').Strategy;
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
//var FacebookStrategy = require('passport-facebook').Strategy;
module.exports= function(passport){
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
ubCust.findById(id,function(err,user){
done(err, user);
})
});
passport.use(new GoogleStrategy ({
clientID: Auth.googleAuth.clientID,
clientSecret: Auth.googleAuth.clientSecret,
callbackURL : Auth.googleAuth.callbackURL
},
function(token, refreshToken, profile, done) {
// Create or update user, call done() when complete...
process.nextTick(function(){
ubCust.findOne({'google.id' : profile.id}, function(err, user) {
if (err)
return done(err);
if(user)
return done(null,user);
else
{
var newUser = new ubCust;
newUser.google.id = profile.id;
newUser.google.token = token;
newUser.google.name = profile.displayName;
newUser.google.email = profile.emails[0].value;
newUser.save(function(err){
if (err)
throw err;
return done(null,newUser);
});
console.log(profile);
}
//done(null, profile, tokens);
}); //findOne
});//nextTick
}
));
};
route(authController.js)
module.exports = function(app,passport){
app.get('/api/getprofauth',isLoggedIn,function(req,res){
console.log('In getprofile authentication api');
//console.log('req.query :',req.query);
res.send(req.user);
});
app.get('/auth/google',
passport.authenticate('google',{scope: ['email','profile']})
);
app.get('/auth/google/callback',
passport.authenticate('google', {failureRedirect: '/'}),
function(req, res) {
console.log('auth success!! ',req.isAuthenticated(),req.user);
res.redirect('/api/getprofauth');
}
);
function isLoggedIn(req,res,next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
{
console.log('isAuthenticated Success');
return next();
}
else{
console.log('req.user',req.user,req.isAuthenticated());
console.log('isAuthenticated Failure');
res.redirect('/');
}
// if they aren't redirect them to the home page
}//isLoggedIn
}
app.js(server)
var express = require('express');
var app = express();
var mongoose = require('mongoose');
var config = require('./config');
var passport = require('passport');
var cookieParser = require('cookie-parser');
app.use(cookieParser());
var session = require('express-session');
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
var authController = require('./controllers/authController.js');
var port = process.env.PORT||3000;
app.use(express.static(__dirname+ '/public'));
app.set('view engine','ejs');
app.get('/',function(req,res){
//redirecting request to home page '/' to index page
res.redirect('/index.htm');
});
mongoose.connect(config.getDBConnectionString());
app.use(passport.initialize());
app.use(passport.session());
var pp = require('./config/passport');
pp(passport);
apiController(app);
apibike(app);
appoController(app);
authController(app,passport);
app.listen(port);

Resources