passport js missing credentials - passport.js

Been working on this for a few hours now, pretty frustrating...
router.post('/', passport.authenticate('local-signup', function(err, user, info) {
console.log(err);
}), function(req, res){
console.log(req);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ a: 1 }));
});
When I run this, i used console.log, output was { message: 'Missing credentials' }, which leads me to believe that the body parser is not properly parsing the body message. When I use this route however...
router.post('/', function(req, res){
console.log(req.body);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify({ a: 1 }));
});
When I used console.log, the output was {password: 'password', email: 'email#email.com'}, which indicates that the req.body variables are being set properly and are available.
app.js
var express = require('express');
var app = express();
var routes = require("./config/routes.config");
var models = require("./config/models.config");
var session = require('express-session');
var bodyParser = require('body-parser');
models.forEach(function(model){
GLOBAL[model] = require('./models/'+model+".model");
});
var passport = require("./config/passport.config");
app.use( bodyParser.urlencoded({ extended: true }) );
app.use(session({ secret: 'simpleExpressMVC', resave: true, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());

I see your req.body contains {password: 'password', email: 'email#email.com'}. email is not what passportjs is looking for, but username is. You can either change your input names on your HTML/JS, or you can change the default parameters passportjs is looking for in req.body. You need to apply these changes where you define your strategy.
passport.use(new LocalStrategy({ // or whatever you want to use
usernameField: 'email', // define the parameter in req.body that passport can use as username and password
passwordField: 'password'
},
function(username, password, done) { // depending on your strategy, you might not need this function ...
// ...
}
));

In Router.post:
router.post('/', passport.authenticate('local-signup', {
successRedirect: '/dashboad',
failureRedirect: '/',
badRequestMessage: 'Your message you want to change.', //missing credentials
failureFlash: true
}, function(req, res, next) {
...

I know there are lots of answers here, but this is as clear as it gets.
From the official passport docs
Passportjs documentation
"By default, LocalStrategy expects to find credentials in parameters
named username and password. If your site prefers to name these fields
differently, options are available to change the defaults."
So if you find yourself with this issue you have two solutions (most probably).
Rename your body parameters in your front-end as username and password
Define to your passport instance how you're going to name them with the following code:
passport.use(new LocalStrategy({
usernameField: 'email', //can be 'email' or 'whateveryouwant'
passwordField: 'passwd' //same thing here
},
function(username, password, done) {
// ...
}
));

There could be a mistake in field-type that's why passport.js is not able to recognize the correct field and gives error .
CORRECTION: check in .ejs file if your username and password fields correctly state type.
type="password" id="password" name="password"//CORRECTLY SPECIFIED.
What you might have done is : Type:"text" in ejs file and told passport to look for type:"password"
Tip : Check for spelling mistakes in type fields.
eg: type:password in ejs & type:Password

In my own case, the cause of this was my body-parser or express configuration, whereby inputs from the form were not received by my application. So I did this:
// configuring express
app.use(express.static(path.join(__dirname, "public")));
// body-parser
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

In my case I just miss spelled usernameField as usernameFiled.
Make sure you spell correctly usernameField and passwordField.

Mine was spelling mistake issue.
I hade usernameFeild: 'email',
However, it should be usernameField: 'email',

if you are using passport local mongoose as a plugin with your user model.
Try this:
passport.use(new LocalStrategy({
usernameField: 'email'
}, User.authenticate()));

In my case add all the field inside of config works:
passport.use(new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
}))

Related

Getting Missing required parameter: scope Passport.js, express

Im using Passport.js with express in my app to login with Google Oauth. But when i try to sign in, i get the following error: invalid parameter value for redirect_uri: Missing authority: http:localhost:3000/google/callback from which when i access localhost:3000/google/callback, i get Missing required parameter: scope. The relevant code:
const express = require("express");
const cors = require("cors");
const mongoose = require("mongoose");
const passport = require("passport");
const app = express();
const port = process.env.PORT || 3000;
require("dotenv").config();
require("./passport-setup")
app.use(passport.initialize())
app.use(passport.session())
app.get('/success', (req, res) => {
res.render("/profile.html")
})
app.get('/login', passport.authenticate('google', { scope: 'email' }));
app.get('/google/callback', passport.authenticate('google', { failureRedirect: '/failed' }),
function(req, res) {
// Successful authentication, redirect home.
res.redirect('/success');
}
);
passport config(relevant code):
const passport = require("passport");
const GoogleStrategy = require("passport-google-oauth2").Strategy
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.CALLBACK_URL,
passReqToCallback: true
},function(request,accessToken,refreshToken,profile,done){
console.log(profile)
return done(null, profile)
}
))
PS: I found this answer but i don't know what he means by 'JSON key'. Maybe the API updated.
Any help would be really appreciated.
Thanks in advance.
EDIT
The callback url I provided to google was not matching my `app.get`. Fixed.
PS: I found this answer but i don't know what he means by 'JSON
key' - the person referred to your GoogleStrategy which is A JSON
object contains zero, one, or more key-value pairs.
/* SECURE COOKIES TRUE MADE GOOGLE SIGN IN / SIGNUP WORK */
I was getting an error when trying to Sign in/up with Google account: Missing required parameter: scope and the following lines of code added before app.use(passport.initialize()); made it work!
if (app.get("env") === "production") {
app.set("trust proxy", 1);
session.cookie.secure = true;
}
You might have to implement express-session to make this work (check the npm website for docs on how to use) but simply declare at the top:
const session = require("express-session");
before app.use(passport.initialize()) add this lines:
app.use(
session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {},
})
);
My callback URL was http:localhost:3000/google/callback
Setting it to /gooogle/callback worked for me.

How can I make Passport login session NOT persistent across Chrome windows and be cookie-based only?

Currently I am using Passport with Express and have a local login strategy implemented, using express-session. The actual logic of the login works fine, but I noticed that once I log in from one tab, as soon as I open another Chrome window (even if it is in Incognito mode), it still shows me as logged in as that same user. I don't want this behavior, so that for testing purposes, I can emulate two different, simultaneously logged in users. Also, when I clear all my local cookies, I would like it to instantly treat me as logged off, but right now it is keeping me logged in (unless I explicitly point my browser to the /logout route which runs req.logout();. Here is the current setup (I left out irrelevant lines of code for brevity):
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
expressSession = require('express-session');
app.use(expressSession({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
passport.use('local-login-strategy', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, function(req, email, password, done) { ... });
app.get('/login', function(req, res) { ... });
app.post('/login', passport.authenticate('local-login-strategy', {
successRedirect: '/dashboard',
failureRedirect: '/login?loginFailedTryAgain'
});
Therefore, after digging around I tried using cookie-session instead by modifying the code as such:
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy,
cookieSession = require('cookie-session');
app.use(cookieSession({ secret: 'keyboard cat', key: 'someKey', cookie: {maxAge: 30 * 24 * 60 * 60 * 1000} }));
passport.use('local-login-strategy', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, function(req, email, password, done) { ... });
app.get('/login', function(req, res) { ... });
app.post('/login', passport.authenticate('local-login-strategy', {
successRedirect: '/dashboard',
failureRedirect: '/login?loginFailedTryAgain',
session: false
});
Unfortunately, that didn't work either.
Any ideas how to tweak this code to achieve my desired results?

upgrading to express 4 passport stopped working

I am upgrading the express 4 and my passport is failing every time now. It is not even logging to the console in passport.use(new LocalStrategy.
It redirects the /failure every time without hitting any breakpoints
// Use the LocalStrategy within Passport.
// Strategies in passport require a `verify` function, which accept
// credentials (in this case, a username and password), and invoke a callback
// with a user object. In the real world, this would query a database;
// however, in this example we are using a baked-in set of users.
passport.use(new LocalStrategy(
function(username, password, done) {
console.log("LocalStrategy working...");
// 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 and set a flash message. Otherwise, return the
// authenticated `user`.
findByUsername(username, password, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {
message: 'Unknown user ' + username
});
} else {
return done(null, user);
}
})
});
}
));
app.use(cookieParser('keyboard cat'));
app.use(session({
secret: 'keyboard cat',
saveUninitialized: true,
resave: true
}));
// Initialize Passport! Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());
app.post('/login', passport.authenticate('local', {
failureRedirect: '/failure',
failureFlash: false
}),
function(req, res) {
res.cookie('userdata', req.user);
switch (req.user.role) {
case 'candidate':
res.redirect('/app/candidates');
break;
case 'employer':
res.redirect('/app/employers');
break;
case 'provider':
res.redirect('/app/providers');
break;
case 'admin':
res.redirect('/app/admin');
break;
default:
break;
}
});
Assuming you have all relevant code included the reason for the failure is likely missing body parser. The authentication strategy will try to find the username and password fields from req.body and req.query, and if there is no body parser used req.body will be empty. The strategy will then fail straight away as it would have nothing to pass to your verify callback.
You need to make the Express application use relevant body parser, for example:
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
Have you included LocalStrategy?
var LocalStrategy = require('passport-local').Strategy;
app.use(express.cookieParser()); // read cookies
app.use(express.bodyParser()); // get information from html forms

Passport local strategy not getting called when email or password empty

I use the following passportjs LocalStrategy:
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
function(username, password, done) {
// ...
}
));
All works fine if I do provide email and password properties in POST request. But if one of then is empty then this middleware don't get executed but redirect happens.
I need to know what happens and pass req.flash to the client to handle this exception. How could I do it?
You could use express-validator. It can check your email/password fields in general that they are not empty.
Just require and use it in your app.js entry point:
var expressValidator = require('express-validator');
app.use(bodyParser());
app.use(expressValidator()); // then let the app use it, place it HERE after the bodyParser()
and in your login/signup route:
router.post('/signup', function (req, res) {
req.assert('email', 'Email is not valid!').isEmail();
req.assert('password', 'Password is empty!').notEmpty();
var err = req.validationErrors();
if (err) {
req.flash('errors', errors);
return res.redirect('/login');
}
// Your passport here....
}
And then do your passport stuff like login or signup.

passport local strategy not getting called

I'm sure I'm missing something really obvious here, but I can't figure this out. The function I've passed to the LocalStrategy constructor doesn't get called when the login form gets submitted.
Code:
var express = require('express');
var http = require('http');
var path = require('path');
var swig = require('swig');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
passport.serializeUser(function(user, done) {
console.log('Serialize user called.');
done(null, user.name);
});
passport.deserializeUser(function(id, done) {
console.log('Deserialize user called.');
return done(null, {name: 'Oliver'});
});
passport.use(new LocalStrategy(
function(username, password, done) {
console.log('local strategy called with: %s', username);
return done(null, {name: username});
}));
var app = express();
app.set('port', process.env.PORT || 3000);
app.set('view engine', 'swig');
app.set('views', __dirname + '/views');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('asljASDR2084^^!'));
app.use(express.session());
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(require('less-middleware')({ src: __dirname + '/public' }));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.errorHandler({ dumpExceptions:true, showStack:true }));
app.engine('swig', swig.renderFile);
app.post('/auth', passport.authenticate('local'));
app.get('/login', function(req, res) {
// login is a simple form that posts username and password /auth
res.render('login', {});
});
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
The form on my /login page is cut and pasted from the passport docs except that I changed it to submit to /auth instead of /login:
<form action="/auth" method="post">
<div>
<label>Username:</label>
<input type="text" name="username"/>
</div>
<div>
<label>Password:</label>
<input type="password" name="password"/>
</div>
<div>
<input type="submit" value="Log In"/>
</div>
</form>
When I sumit the login form, the following gets logged
GET /login 200 5ms - 432b
POST /auth 401 6ms
Note that "local strategy called" is never logged.
Why isn't the function I passed to LocalStrategy getting called?
I recently came across this problem and it can be caused by a number of things. First thing to check is ensuring that the bodyParser is set up for express, which I see that you have done.
app.use(express.bodyParser());
The next thing is ensuring that the form you are submitting to the route contains both a username AND password, and the user must also enter something in both fields. I was stumped for a bit testing it and not actually putting anything in the password field while testing :) Passport requires BOTH to execute the LocalStrategy verification function passed to passport.authenticate('local').
Your example also seems to be set up to capture both username and password properly, but in any case, you should try testing that the body is being parsed properly even without passport:
app.post('/auth', function(req, res){
console.log("body parsing", req.body);
//should be something like: {username: YOURUSERNAME, password: YOURPASSWORD}
});
Else
Did you try adding a request handler to your /auth route?
app.post('/auth', passport.authenticate('local'), function(req, res){
console.log("passport user", req.user);
});
or
app.post('/auth', passport.authenticate('local', { successRedirect: '/', failureRedirect: '/auth' }));
I encountered the same problem when I set up my own route handler from which I called passport.authenticate (). I forgot that passport.authenticate returns middleware that must be invoked, so just calling passport.authenticate isn't sufficient. Then I replaced
router.post("/",
function(req,res,next){
passport.authenticate("local", function(err, user, info){
// handle succes or failure
});
})
with
router.post("/",
function(req,res,next){
passport.authenticate("local", function(err, user, info){
// handle succes or failure
})(req,res,next);
})
You get 401 when you using different username, password input fields than the default ones. You have to provide that in your LocalStrategy like this :
passport.use(new LocalStrategy({
usernameField: 'login',
passwordField: 'password'
},
function(username, password, done) {
...
}
));
Default is username and password I think. See the docs here.
I think you submit the form with username or password field empty.
If you fill both inputs then submit, LocalStrategy will be called.
For Express 4.x:
// Body parser
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false })) // parse application/x-www-form-urlencoded
app.use(bodyParser.json()) // parse application/json
c.f. https://github.com/expressjs/body-parser
I also banged my head for the same problem for few hours. I was having everything in place as told by other answers like
1. Form was returning all fields.
2. body parser was setup correctly with extended:true
3. Passport with every setting and configuration.
But i have changed username field with phoneNumber and password. By changing code like below solved my problem
passport.use('login', new LocalStrategy(
{usernameField:'phoneNumber',
passwordField:'password'},
function (username, password, done) {
// your login goes here
})
);
If anyone want i can write the whole authentication procedure for phonenumber using mongodb and passport-local.
Thanks #user568109
My problem was, that I had the enctype='multipart/form-data'. Just change that to multipart='urlencoded'. And I think that will solve it.
To capture both username and passport make sure to add:
app.use(express.urlencoded());
In my case, I was using app.use(express.json()); and was posting the username and password from <form>.
It's possible your request wasn't formatted properly (particularly the body of it) and your username and password weren't being sent when you thought they were.
Here is an example of an API call wrapper that enforces your request body is parsed as json:
Api = {};
Api.request = (route, options) => {
options = options || {};
options.method = options.method || 'GET';
options.credentials = 'include';
if (options.method === 'POST') {
options.headers = {
'Accept': 'application/json',
'Content-Type': 'application/json',
};
options.body = JSON.stringify(options.data) || '{}';
}
fetch(absoluteUrl + '/api/' + route, options)
.then((response) => response.json())
.then(options.cb || (() => {}))
.catch(function(error) {
console.log(error);
});
};
It can be used this way:
Api.request('login', {
data: {
username: this.state.username,
password: this.state.password
},
method: 'POST',
cb: proxy((user) => {
console.log(user);
}, this)
});
For me everything was setup properly.. The issue was that I was collecting form data and then creating a json from form data and send it like JSON.stringify(formdatajson) to server. (For me login form was a popup on screen)
I Found my mistake by debugging passportjs...
If you also have same problem and none of the above solution seems working for you then debug passportjs.
open
strategy.js
put debugger in below method.
Strategy.prototype.authenticate
Check what form data is coming for you.
Hope this help ...
npm install passport-local
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
According to passportjs.org and it worked for me!
Yet another possiblity: For me I had accidentally defined my routes before my body-parser middleware so body-parser was never active for the login route.
Hope it always someone - in my case it was the fact that I tried I used passport middleware before cookieParser and express-session ones
This was my code:
passportConfig(app);
app.use(cookieParser());
app.use(session({ secret: 'bla' }));
Changed passportConfig to be down and it worked:
app.use(cookieParser());
app.use(session({ secret: 'bla' }));
passportConfig(app);
For me it wasn't working because i'd set different name in my login form to that in my passport.js ,It worked for me when i changed user.name in serializeUser to user.username.
passport.serializeUser(function (user, done) {
done(null, user.username)
})
passport.deserializeUser(function (username, done) {
Users.findOne({
username: username
}).then((user) => {
if (!user) {
return done(new Error("No such user"))
}
return done(null, user)
}).catch((err) => {
done(err)
})
})
Check your form in your views if you included a name property in the form or input type and it corresponds to the arguments passed to the localStrategy callback function.

Resources