I am new to the whole user authentication things with node and I am trying to learn how to use Passport's LocalStrategy to add users to a Mongo database.
I'm trying to follow a particular tutorial and for some reason things aren't going to plan. Whenever I submit the registration form the strategy always fails (is redirected to the failure page). I have a feeling it is something to do with the body of he request not being passed (since the log I placed in where the strategy is declared is not run). However it seems like the current infrastructure makes it hard to refactor. Can this code be refactored such that the request can be parsed manually (e.g. request.body.* name *) before handing it over to passport?
Unless the issue is something completely different, in which case I have no idea...
index.js:
// Use middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(expressSession({ secret: 'whatkindofgamedoyouthinkthisishey',
cookie: {maxAge:null},
resave: false,
saveUninitialized: false}));
require("./config/passport")(passport);
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
// Obtain application modules
var userModels = require("./schemas/user")(mongoose);
var loginPage = require("./routes/login")(passport, userModels);
// Initialize Routes
app.use("/", loginPage);
passport.js (should come up with a better name):
var LocalStrategy = require("passport-local").Strategy,
User = require("../schemas/user");
module.exports = function (passport) {
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("local-signup", new LocalStrategy({
email: "email",
password: "password",
passReqToCallback: true
},
function (request, email, password, done) {
console.log("message sent to sign up"); // log not running
process.nextTick(function () {
User.findOne({email: email}, function (err, user) {
if (err) {
return done(err);
}
if (user) {
return done(null, false, request.flash("signupMessage", "That email is already taken"));
} else {
var newUser = new User();
newUser.email = email;
newUser.password = password;
newUser.save(function (err) {
if (err) {
throw err;
} else {
return done(null, newUser);
}
});
}
});
});
}
));
};
login.js (router being exported)
router.post("/register", passport.authenticate("local-signup", {
successRedirect: "/loggedIn",
failureRedirect: "/connectFailed",
failureFlash: false
}));
Html form:
<form class="form-signin" action="/register" method="POST">
<div class="logoContainer">
<img src="images/LogoWithoutText.png" class="image image-responsive" id="loginImage">
</div>
<h2 class="form-signin-heading">Please sign in</h2>
<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" id="inputEmail" class="form-control" name="email" placeholder="Email address" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword" class="form-control" name="password" placeholder="Password" required>
<div class="checkbox">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
From what I can read in the passportjs.org/docs, it looks like passport.use has the following signature:
var passport = require('passport'),
LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy({
email: "email",
password: "password",
passReqToCallback: true
},
function(req, email, 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);
});
}
));
So, try changing the way passport.use is written and try you luck.
Related
When i sign up a new mail it's redirect to logIn page, in router.post('/login') I added successRedirect: '/' and
failureRedirect: '/test' but it in anyway it redirect to /test even if it's success!
index.js
var express = require('express');
var router = express.Router();
const users = require('../model/db');
const { check, validationResult } = require('express-validator');
const passport = require('passport');
//GET login
router.get('/login', (req, res, next)=>{res.render('login')});
router.post('/login', passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/test',
failureFlash: true,
}));
router.get('/signup', function (req, res, next){
const msg = req.flash('error')
res.render('signup');
});
router.post('/signup', [
check('password').isLength({ min: 5 }).withMessage('Please enter Password with more than 5 letters!'),
check('password').not().isEmpty().withMessage('Please fill password fie'),
check('repassword').custom((val, {req})=>{
if(val !== req.body.password){
throw new Error('Password is not equal to confirm password');
}
return true;
})
],
function (req, res, next){
const newUser = new users({
email : req.body.email,
password : new users().hashPassword(req.body.password)
});
users.findOne({email : req.body.email}, (err, doc)=>{
if(err){
console.log('ERR while getting username =>' + err);
return ;
}
if(doc){
res.send('this email is already registered before!');
return ;
}
newUser.save((err, doc)=>{
if(err){
console.log('err' + err)
}else{
res.redirect('/login')
}
});
});
// Finds the validation errors in this request and wraps them in an object with handy functions
const errors = validationResult(req);
if (!errors.isEmpty()) {
var validationMessage = [];
for(var i = 0; i<errors.errors.length; i++){
validationMessage.push(errors.errors[i].msg);
}
req.flash('error', validationMessage)
res.redirect('signup')
}
});
module.exports = router;
According to these two lines of code,
router.post('/login', passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/test',
failureFlash: true,
}));
It should Redirect me to /test if it failed and To / if it succeeded
login.hbs
<div class="container">
<div class="s-f">
<div class="card">
<div class="card-body">
<div>
<h6>Log in | Coursatak</h6>
</div>
<form action="/login" method="post">
<div class="form-group">
<label for="email">Email</label>
<input type="text" name="email" id="email" class="form-control">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" name="password" id="password" class="form-control">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary"> Sign Up</button>
</div>
<div>
<p class='if'></span>Sign Up, <span>If you already registered before.</p>
</div>
</form>
</div>
</div>
</div>
</div>
config/conficuration.js
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcryptjs');
const User = require('../model/students');
module.exports = function(passport) {
passport.use(
new LocalStrategy('local', { usernameField: 'email' }, (email, password, done) => {
// Match user
User.findOne({email: email}).then(user => {
if (!user) {
return done(null, false, { message: 'That email is not registered' });
}
bcrypt.compare(password, student.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Password incorrect' });
}
});
});
})
);
};
Schema
const mongoose = require('mongoose');
const bcrypt = require('bcrypt-nodejs');
const stDB = mongoose.Schema({
email : {
type: String,
required: true
},
password : {
type: String,
required: true
}
});
stDB.methods.hashPassword = function(password){
return bcrypt.hashSync(password, bcrypt.genSaltSync(10));
}
stDB.methods.comparePasswords = (password, hash) => {
return bcrypt.compareSync(password,hash)
}
module.exports = mongoose.model('db', stDB);
Node Version: 10.16.1
Express Version: 4.16.1
I dont know what you have at your app.js file , however paste the following code snippet at your app.js file and dismiss the config/conficuration.js
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
//after your modules
//passport login local login system
passport.serializeUser(function (user, done) {
//console.log('in serializeUser method user:' + user);
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
//console.log('in deserializeUser method id:' + id);
User.findById(id, function (err, user) {
done(err, user);
});
});
passport.use(
new LocalStrategy('local', { usernameField: 'email' }, (email, password, done) => {
// Match user
User.findOne({email: email}).then(user => {
if (!user) {
return done(null, false, { message: 'That email is not registered' });
}
bcrypt.compare(password, student.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Password incorrect' });
}
});
});
})
);
//after you initialize your sessions
app.use(passport.initialize());
app.use(passport.session());
m trying to make auth system with react and Passport js
My passport look like this:
let passport = require('passport');
let User = require('../models/user');
let localStorage = require('passport-local').Strategy;
passport.serializeUser(function(user, done){
done(null, user.id)
});
passport.deserializeUser(function(id, done){
User.findById(id, (err, user) => {
done(err, user)
})
});
passport.use('local.signup', new localStorage({
usernameField: 'email', passwordField: 'password', passReqToCallback: true
}, function(req, email, password, done){
//Check valid
req.checkBody(req.body.email, 'Invalid email').notEmpty().isEmail();
req.checkBody(req.body.password, 'Invalid password').notEmpty().isLength({min: 4});
req.checkBody(req.body.name, 'Name is require!').notEmpty();
let errors = req.validationErrors(); //Get all errors for checkBody
if(errors){
let messages = [];
errors.forEach(function(error){
messages.push(error.msg)
});
return done(null, false, req.flash('error', messages));
}
User.findOne({'email': req.body.email}, function(err, user){
if(err) return done(err);
if(user) return done(null, false, {message: 'Email is already in use'});
var newUser = new User();
newUser.email= req.body.email;
newUser.password = newUser.encryptPassword(req.body.password);
newUser.name = req.body.name;
newUser.save((err, user) => {
if(err) return done(err);
return done(null, user);
})
})
}));
My route file:
const express = require('express');
const passport = require('passport');
let router = express.Router();
let User = require('../models/user');
router.post('/signup', passport.authenticate('local.signup', {
failureRedirect: '/', failureFlash: true
}), function(req, res,next){
console.log('Yes signUp');
});
module.exports = router;
React file:
handleChange = ev => {
this.setState({[ev.target.name]: ev.target.value});
}
onSubmit = ev => {
ev.preventDefault();
let user = {
name: this.state.name,
email: this.state.email,
password: this.state.password
}
axios.post('http://localhost:3001/signup', user)
.then(res=> { console.log(res) })
.catch(err=> { console.error(err) })
}
render() {
return (
<div className="container login-container">
<div className="title-login text-center">Login</div>
<hr/>
<div className="login-form">
<div className="form-group">
<input type="email" className="form-control" name="email" value={this.state.email} placeholder="Enter your Email.." onChange={this.handleChange} />
</div>
<div className="form-group">
<input type="text" className="form-control" name="name" value={this.state.name} placeholder="Enter your Name.." onChange={this.handleChange} />
</div>
<div className="form-group">
<input type="password" className="form-control" name="password" value={this.state.password} placeholder="Enter your password.." onChange={this.handleChange} />
</div>
<button className="btn btn-outline-primary btn-block" onClick={this.onSubmit}>Send</button>
</div>
</div>
)
}
The error is:
OPTIONS http://localhost:3001/ 404 (Not Found) signup:1 Failed to load
http://localhost:3001/: Response for preflight has invalid HTTP status
code 404. index.js:2178 Error: Network Error
at createError (createError.js:16)
at XMLHttpRequest.handleError (xhr.js:87)
Help!
I have been trying to get local authentication work with passport on nodejs and as far as i can tell all of my code it is correct but i keep getting the same annoying error about "unknown authentication strategy so maybe someone else can help me with this problem my code is shown below.
Here is my code for passport configuration in nodejs.
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
module.exports = function(passport) {
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('local-signup', new LocalStrategy({
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true
},
function(req, username, password, done) {
process.nextTick(function() {
User.findOne({ 'local.username' : username}, function(err, user) {
if (err)
return done(err);
if(user) {
return done(null, false, req.flash('signupMessage', 'That Username is already taken.'));
}
else {
var newUser = new User();
newUser.local.username = username;
newUser.local.password = newUser.generateHash(password);
newUser.save(function(err) {
if(err)
throw err;
return done(null, newUser);
});
}
});
});
}));
passport.use('local-login', new LocalStrategy({
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true
},
function(req, username, password,done) {
User.findOne({ 'local.username' : username}, function(err, user) {
if(err)
return done(err);
if(!user)
return done(null, false, req.flash('loginMessage', 'No user found.'));
if(!user.validPassword(password))
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.'));
return done(null, user);
});
}));
};
And here is the post on the server side.
app.post('/signin', passport.authenticate('local-login', {
successRedirect : '/profile',
failureRedirect : '/login',
failureFlash : true
}));
And here is the form in the html doc
<div id="signin">
<form class="form-horizontal" method="POST" action="/signin">
<div class="form-group">
<label class="control-label col-sm-2">Username:</label>
<div class="col-xs-3">
<input type="text" class="form-control"></input><br>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Password:</label>
<div class="col-xs-3">
<input type="password" class="form-control"></input><br><br>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default btn-lg">Sign In</button><br><br>
</div>
</div>
</form>
<div id="accountlinks">
Create Account<br>
Forgot Password
</div>
</div>
Can anyone please help me by telling me what i have done wrong. thanks
require('./config/passport')(passport);
Change the path of the file. Without this working, passport's configurations will not be passed to the routes.
Here is a snippet of where the line should be located:
// server.js
// configuration
===============================================================
mongoose.connect(configDB.url); // connect to our database
require('./config/passport')(passport); // pass passport for configuration
I also had the same problem but when I put this line of code after the app.use(flash()) it worked:
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
require('./config/passport')(passport);
I want to make ajax login with the passport.js. I have the usual code for setting the passport.js:
//route
app.post('/api/auth/login', passport.authenticate('local-login', {
successRedirect: '/',
failureRedirect: '/login'
}));
//config strategy
passport.use('local-login', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
}, loginUser));
var loginUser = function(req, email, password, done) {
UserRepo.getOne({
'local.email': email
}).done(function(user) {
if (!user || !user.validPassword(password)) {
return done(null, false, {
message: 'user or password is incorrect'
});
}
return done(null, user);
},
function(err) {
return done(err);
});
};
This is my react component:
var Login = React.createClass({
//...
handleSubmit: function (e) {
e.preventDefault();
var email = this.state.email.trim();
var password = this.state.password.trim();
var data = {
email: email,
password: password
};
api.auth.login(data, function (result) {
console.log(result);
});
},
render: function () {
return (
<form className="login-form" onSubmit={this.handleSubmit}>
<section>
<label>email</label>
<input name="email" type="text" />
<label>password</label>
<input name="password" type="password" />
</section>
<section>
<input type="submit" value="send"/>
</section>
</form>
);
}
//...
})
But, it doesn't work, because redirects (successRedirect and failureRedirect) do their work. If I delete failureRedirect I get 401 status. I understand that my code for passport for server side rendering and page refresh, but I cannot find any documentation for ajax login.
You can use a custom callback to return JSON data.
app.post('/api/auth/login', function(req, res, next) {
passport.authenticate('local-login', function(error, user, info) {
if(error) {
return res.status(500).json(error);
}
if(!user) {
return res.status(401).json(info.message);
}
res.json(user);
})(req, res, next);
});
I'm new to node and am trying to get a simple local login up and running using passport.js. It looks to me that the strategy that I have set up is not being run when the authenticate function is called.
module.exports = function(app) {
var mongo = require('./mongoose-db.js');
var brands = require('./app/brands.js');
// brand admin page //
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy( {//this is a strategy but why is it not being run?
usernameField: 'admin_username',
passwordField: 'admin_password'
},
function(username, password, done) {console.log('here 7');
process.nextTick(function () {
console.log('here 8');
// 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`.
mongo.findAdminByUsername(username, function(err, user) { console.log('here 9');
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Unknown Admin ' + username }); }
if (user.password != password) { return done(null, false, { message: 'Invalid password' }); }
return done(null, user);
})
});
}
));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
findById(id, function (err, user) {
done(err, user);
});
});
app.get('/brand_admin', function(req, res){
console.log('here 1');
res.render('admin_login', { user: req.user, message: req.session.messages });
});
app.post('/brand_admin', function(req, res, next) {
console.log('USER: ');
console.log(req.user);
res.send('ok');
passport.authenticate('local', function(err, user, info) {
console.log(user);
if (err) { return next(err) }
if (!user) {console.log(req.session.messages);
req.session.messages = [info.message];
console.log('here 4');
console.log(req.session.messages);
return res.redirect('/brand_admin')
}
console.log('here 5');
req.logIn(user, function(err) {
if (err) { return next(err); console.log('here 6');}
return res.redirect('/');
});
})(req, res, next);
});
the ejs is:
<body>
<head> Admin Login </head>
<form id="brand_edit" action="/brand_admin" method="post" >
<fieldset>
Login: <input type="text" name="admin_login" > <br>
Password: <input type="password" name="admin_password" >
<input type="submit" name="action" value="Login"/>
</fieldset>
Forgotten your password?
</form>
</body>
The output i'm getting from form submission is:
Steve
agrgegerfe
{ id: 1,
username: 'Steve',
password: 'agrgegerfe',
email: 'bob#example.com' }
false
undefined
here 4
[ 'Missing credentials' ]
here 1
The strategy is not running but I can't figure out why? Can anyone help? One thing that could be affecting this is that I am using passport for Facebook login in another section of the application..
I think you are not calling passport properly. It needs to be in the route chain. Try this:
// configure passport with the correct fields
passport.use(new LocalStrategy({
usernameField: 'admin_login',
passwordField: 'admin_password'
}, function (username, password, done) {
...
});
app.post('/brand_admin', passport.authenticate('local'), function (req, res) {
// req.user is now defined
console.log(req.user);
res.send('ok');
});