I am using passport and trying to do my code organisation like routes(just one line route), controller with one method to handle route, model to do some action which coming from controller method. Following code is working fine returning me token if mobile number and password is matched. But how can I reorgnize code so it break and become properly, I dont' want to put anything in routes.js file but just one single line, and nothing in controller but one method where I want to put all passport stuff in passport.js file either config/passport.js or root/passport.js
const express = require('express'),
cors = require('cors'),
compression = require('compression'),
morgan = require('morgan'),
passport = require('passport')
const app = express()
app.use(passport.initialize())
app.use(express.json())
app.use(express.urlencoded({extended: false}))
app.use('/', Router)
Now in my config/routes.js file
const passport = require('passport')
const userController = require('../app/controllers/users_controller')
const jwt = require('jsonwebtoken')
LocalStrategy = require('passport-local').Strategy
passport.use(
new LocalStrategy(function (username, password, done) {
User.findOne({mobile: username}, function (err, user) {
if (err) {
return done(err)
}
if (!user) {
return done(null, false, {message: 'Incorrect Username'})
}
console.log(` Password: ${password} `)
if (!user.comparePassword(password)) {
return done(null, false, {message: 'Incorrect password'})
}
return done(null, user)
})
})
)
passport.serializeUser(function (user, cb) {
cb(null, user.id)
})
passport.deserializeUser(function (id, cb) {
User.findById(id, function (err, user) {
if (err) {
return cb(err)
}
cb(null, user)
})
})
router.post('/api/v1/login', function (req, res, next) {
passport.authenticate('local', {session: false}, (err, user, info) => {
if (err || !user) {
return res.status(400).json({
message: 'Something is not right',
user: user,
})
}
req.login(user, {session: false}, (err) => {
if (err) {
res.send(` Error: ${err}`)
}
// generate a signed son web token wtih contents of user
const token = jwt.sign(user.id, 'your_jwt_secret')
return res.json({user, token})
})
})(req, res)
})
I want to break it, it should not be in routes, my other routes are like following
router.get('/logout', users_controller.update)
router.post('/forgotPassword', users_controller.update)
I want to that it should be like following route
router.post('/login', users_controller.login)
I tried many times but still can't work out, even used this code, but in my another website I used same method and it worked in Controller, so all passport related stuff I put in controller but that one is also not correct, it should be one line in route file and method in controller rest in separate passport.js files.
Kindly can you assist me how can I do it?
Related
I am trying to set up basic authentication with Passport.js LocalStrategy but I am re-routed to the successRedirect (res.redirect('../public/index.html') even with incorrect username/password entered in the login form.
My db.query() calls are returning correct results on other routes so I think the issue is in another part of the code but I just don't see where at this stage.
My understanding of the use of "user" vs. "username" in the LocalStrategy is hazy and potentially where the issue lies?
If any one is able to spot the issue i'd be most grateful.
(Note, I have stripped back the snippet below to remove the hash and crypto/bcrypt features just to get the bare bones working before implementing some basic security methods)
const express = require('express');
const loginRouter = express.Router();
const path = require('path');
const passport = require('passport');
const session = require('express-session');
const LocalStrategy = require('passport-local');
const db = require('../db/db');
// Define session (update secret to env variable once working).
loginRouter.use(
session({
secret: "D53gxl41G",
resave: false,
saveUninitialized: false,
})
);
loginRouter.use(passport.initialize());
loginRouter.use(passport.session());
passport.use(new LocalStrategy(function (username, password, done) {
db.query('SELECT * FROM customers WHERE username = $1', [username], function(err, user) {
if (err) return done(err);
if (!user) return done(null, false);
if (user.password != password) return done(null, false);
return done(null, user);
});
})
);
// GET log in page
loginRouter.get('/', (req, res, next) => {
res.status(200).sendFile(path.resolve('./public/auth.html'));
});
// POST form submission w/passport authentication. Not showing errors even with incorrect username/passwords.
loginRouter.post('/', passport.authenticate('local',
{ failureRedirect: '/' }),
(req, res) => {
res.redirect('../public/index.html');
}
);
module.exports = loginRouter;
SELECT will return an object. That object has a property rows listing any matching row from the database. In your code, that object is user. And to get the one item matching the SELECT query you would do user.rows[0]. Comparing the password:
if (user.rows[0].password != password) return done(null, false);
I suggest that you rename user to res then create a variable such as:
db.query('SELECT * FROM customers WHERE username = $1', [username], function (err, res) {
const user = res.rows[0]
if (err) return done(err);
if (!user) return done(null, false);
if (user.password != password) return done(null, false);
return done(null, user);
});
I'm trying to create an application that utilizes a registration and login functionality. I have completed the registration portion where all the information (Email and Password) is successfully passed and saved into a MySQL database.
Problem: My issue now is that when I put in any existing credential and email, the application will hang and refuse to redirect the user to a new page. On the bottom of my browser, it will say "Waiting for localhost...". If I leave the page up for too long, it'll eventually lead to an error page with the words "This page isn’t working. localhost didn’t send any data. ERR_EMPTY_RESPONSE".
I tried console logging for any errors but was unable to identify any causes/errors. I did ensure that the information I inputted is properly being compared to the values in the database table and that the redirection to the page is functioning. I also tried rewriting my code in multiple ways but ended up encountering the same issue.
Below is my passport.js file:
var LocalStrategy = require('passport-local').Strategy;
// Load User model
const User = require('../models/User');
// Reference: http://www.passportjs.org/docs/
module.exports = function (passport) {
passport.use(
new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
// Match user
User.findOne({ which: { email: email } })
.then(user => {
// Check if Email exists in database
if (!user) {
return done(null, false, {
message: "Email is not registered."
});
}
// Check if password matches the one found in the database (To Do: Encrypt this later!)
if (password != user.password) {
return done(null, false, { message: 'Password is incorrect.' });
} else {
return done(null, user);
}
})
.catch(err => console.log(err));
})
);
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
// Find by Primary Key
User.findByPk(id, function (err, user) {
console.log(user);
done(err, user);
});
});
}
Below is my app.js (server) file:
var express = require('express')
var expressLayouts = require('express-ejs-layouts');
var flash = require('connect-flash');
var session = require('express-session');
var passport = require('passport');
var app = express();
// Embedded JavaScript (EJS)
app.use(expressLayouts);
app.set('view engine', 'ejs');
// Express Session
app.use(session({
secret: 'secret',
resave: false,
saveUninitialized: false
}));
// Bodyparser
app.use(express.urlencoded({ extended: false }));
// Passport
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);
// Connect flash for notification messages
app.use(flash());
// Global Variables to define specific notification messages
app.use((req, res, next) => {
// Notification for Registration Page
res.locals.success_msg = req.flash('success_msg')
res.locals.error_msg = req.flash('error_msg');
// Notification for Passport Login Verification
res.locals.error = req.flash('error');
next();
});
// Routes
app.use('/', require('./routes/index'));
// Login/Register Endpoints routes (ex. /users/login)
app.use('/users', require('./routes/users'));
// Image
//app.use(express.static('./public'));
var port = process.env.PORT || 8026;
app.listen(port);
console.log('Server Running');
console.log("Port: " + port);
Below is my function to handle the login and redirection:
router.post('/login', (req, res, next) => {
console.log(req.body);
passport.authenticate('local', {
successRedirect: '/dashboard',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
});
Please let me know if you need any other information. Thank you!
I think this could be a problem. On passport.use , if an error occurred, you are not returning anything.
passport.use(
new LocalStrategy({ usernameField: 'email' }, (email, password, done) => {
// Match user
User.findOne({ which: { email: email } })
.then(user => {
// Check if Email exists in database
if (!user) {
return done(null, false, {
message: "Email is not registered."
});
}
// Check if password matches the one found in the database (To Do: Encrypt this later!)
if (password != user.password) {
return done(null, false, { message: 'Password is incorrect.' });
} else {
return done(null, user);
}
})
.catch(err =>{
console.log(err));
return done(null, false, { message: 'Internal Server error.' });
}
})
Fixed the hanging issue. It was indeed something wrong with the way I wrote passport.js as the code works more for MongoDB rather than MySQL.
Here is the new working passport.js:
module.exports = function(passport) {
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
connection.query("select * from users where id = "+id,function(err,rows){
done(err, rows[0]);
});
});
passport.use(new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows pass back of entire request to the callback
},
function(req, email, password, done) { // callback with email and password from form
// Match User
connection.query("SELECT * FROM `users` WHERE `email` = '" + email + "'",function(err,rows){
if (err)
return done(err);
// Check if Email exists in database
if (!rows.length) {
return done(null, false, { message: 'Email is not registered' });
}
// Check if password matches the one found in the database (To Do: Encrypt this later!)
if (!( rows[0].password == password))
return done(null, false, { message: 'Password is incorrect.' });
// All is well, return successful user
return done(null, rows[0]);
});
}));
};
I was writing a local-signup strategy and noticed that it doesn't work so I stepped back and tried to authenticate against my empty collection. Every time I submit the form it takes ~30-40s until it results in a timeout. I ensured passport.authenticate() is called but it seems ike it's not doing any redirects and hence it is timing out because I am not rendering something either.
Questions:
I expected that it would do a redirect to the failureUrl (which is '/signup'), but instead nothing is happening. What am I doing wrong here?
Why there is no single log message coming from passport? This is driving me crazy because I have absolutely no idea what is going wrong there.
I am new to node.js and as far as I got I don't need to pass the configured passport object to the router but instead I can just do const passport = require('passport') is that correct?
This is my function handler for the /signup route:
function processSignup (req, res) {
logger.info("POST request received")
logger.info(req.body)
passport.authenticate('local', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
})
}
Winston prints:
7:32:04 PM - info: POST request received 7:32:04 PM - info:
username=dassd#dass.de, password=dasdsa, submit=Register
My passport.js file looks like this:
const LocalStrategy = require('passport-local').Strategy
const User = require('./user-model')
const passport = require('passport')
// expose this function to our app using module.exports
function config() {
passport.serializeUser(function(user, done) {
done(null, user.id)
})
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user)
})
})
passport.use(new LocalStrategy(
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);
});
}
));
}
module.exports = {
config: config
}
The relevant snipped of my app.js:
// required for passport
require('./authentication/passport').config();
app.use(cookieParser())
app.use(bodyParser())
app.use(session({
secret: 'secretToBeChanged',
saveUninitialized: false,
resave: false
}))
app.use(passport.initialize())
app.use(passport.session()) // persistent login sessions
app.use(flash()) // use connect-flash for flash messages stored in session
After a quick look at the documentation for passportjs, I think you need to do something like this:
function processSignup (req, res, next) {
logger.info("POST request received")
logger.info(req.body)
const handler = passport.authenticate('local', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
});
handler(req, res, next);
}
passport.authenticate() returns a function that is meant to be used as the route handler function.
Normally, you would type something like:
app.post('/login', passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}));
But since you have abstracted with your own route handler function, you need to invoke the one returned from passport.authenticate().
In the end Mikael Lennholm was right and he pointed me into the right direction. I couldn't find that in any passport.js tutorials. However the passport.js documentation contains this code snippet which represents the same but I prefer it's code style:
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
I'm using angular to deal with some routes,on the server side I'm using passport so basically I can acess to the user session variable req.user in my views , but when it comes to a route renderred by ui-router my req.user is undefined. Any idea to access to the req.user even it's not an express route
app.js code :
// Express Session
app.use(session({
secret: 'secret',
saveUninitialized: true,
resave: true
}));
// Passport init
app.use(passport.initialize());
app.use(passport.session());
// Global Vars
app.use(function (req, res, next) {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
res.locals.user = req.user || null;
next();
});
my passport code is as follows :
passport.use('employee',new LocalStrategy(
function(email, password, done) {
Employee.getUserByEmail(email, function(errEmp, emp){
if(errEmp ) throw errEmp;
if(!emp){
return done(null, false, {message: 'Unknown User'});
}
if(emp) {
Employee.comparePassword(password, emp.encryptedpass, function (err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, emp);
} else {
return done(null, false, {message: 'Invalid password'});
}
});
}
});
}
));
router.get('/',ensureAuthenticated ,function(req, res, next) {
res.render('index', { title: 'Nubes' });
});
function ensureAuthenticated(req, res, next){
if(req.isAuthenticated()){
Employee.findById(req.user.id,function (err,emp) {
if(emp) {
res.render('employee/index');
}
})
}
}
router.post('/login', function(req, res, next) {
Employee.findOne({email:req.body.username},function (err,emp) {
if(emp){
passport.authenticate('employee', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res, next);
})
});
In my rendered page 'employee/index' I can display my user information but routes that rendered by ui-router don't have a user variable
here is an example code of angular route :
$stateProvider
.state('home',{
url:'/',
templateUrl:'/views/employee/home.html'
})
in home.html user is not defined which is normal because it's not express server who rendred it . what I want is to get this user variable in my ui-router rendered pages
I suggest to implement token based authentication using something like JWT-tokens, you have also passport plugins for those.
If you still want to use sessions based info and pass it to the client, you can store them in some global JS variable, which i highly dont recommend.
here some info about jwt: https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens
for the locals if using handlebars it would look something like this:
<script>
var user = {{user}};
</script>
just note that you might need to implement some JSON stringify and decoding in order to get the info as JS object.
I am using express and passport to build a rest api backend and it seems that my localStrategy is not getting called on request.
The entry point of my application looks like the following:
app.js
var fs = require('fs');
var express = require('express');
var mongoose = require('mongoose');
var passport = require('passport');
var config = require('./config/config');
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = express();
app.use(morgan('dev')); // log every request to the console
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser.urlencoded({extended:true}));
app.use(passport.initialize());
//connect to mongodb
mongoose.connect(config.db, options);
//load models (shorten forEach)
...
require(__dirname + '/models/' + file)(mongoose);
//load passport config
require('./config/passport')(mongoose, passport);
//load routes
require('./config/routes')(app, passport);
//start server
var server = app.listen(3000, ....
routes.js
...
app.post('/auth', function(req, res){
console.log("reached auth endpoint");
console.log(req.body);
passport.authenticate('local', { session: false}, function(err, user, info){
console.log("Test:"+user);
if(err) {
console.log("Error1");
return next(err)}
if(!user){
console.log("Error2");
return res.json(401, {error: 'Auth Error!'});
}
console.log("Error3");
var token = jwt.encode({ username: user.email }, "hanswurst");
res.json({token: token});
}),
function(req, res){
console.log("passport user", req.user);
};
});
passport.js
...
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true
},
function(email, password, done){
console.log("TEST");
User.findOne({'email': email}, function(err, user){
if(err){
console.log("Unknown error");
return done(err);
}
if(!user){
console.log("No User found");
return done(null, false);
}
if(!user.validPassword(password)){
console.log("Password was incorrect");
return done(null, false);
}
console.log("User was found");
return done(null, user);
});
}
));
The only result i get on form request is
reached auth endpoint
{ email: 'test#mail.com', password: 'secret' }
POST /auth - - ms - -
For me the request body looks fine and it should enter my LocalStrategy. I am bit helpless as i am not getting any other console output from this point.
First off, you have some basic javascript syntax errors in routes.js. This part right here (lots of code removed for clarity) is broken:
passport.authenticate(/*...*/), function(req, res) {/*..*/};
It might have been that you just added some console.log calls in the wrong place. To clear up the confusion, passport.authenticate() does not perform the authentication right away, what it does is return a middleware for you. You would use it like this for example :
var middleware = passport.authenticate(...);
app.post('/auth', middleware);
So to fix your problem, try invoking the middleware returned by authenticate right away, like this:
app.post('/auth', function(req, res, next) {
console.log("reached auth endpoint");
console.log(req.body);
passport.authenticate('local', {
session: false
}, function(err, user, info) {
console.log("Test:" + user);
if (err) {
console.log("Error1");
return next(err);
}
if (!user) {
console.log("Error2");
return res.json(401, {
error: 'Auth Error!'
});
}
console.log("Error3");
var token = jwt.encode({
username: user.email
}, "hanswurst");
res.json({
token: token
});
})(req, res, next);
});
Also, I have to tell you that require caches modules. To make config/passport.js aware of mongoose and passport, you should not feed them as parameters like this:
require('./config/passport')(mongoose, passport);
Simply require them again inside config/passport.js like so:
// (in config/passport.js)
// Both of these vars point to the same thing you require'd in app.js
var mongoose = require('mongoose');
var passport = require('passport');
[Edit] I Found the problem. Because Express is no longer supporting subpackages like body-parser etc, you need to set those separately. All would be well had I done that in the first place, but I only activated:
app.use(bodyParser.urlencoded({extended:true}));
You also need to set
app.use(bodyParser.json());
To get it to work properly. Stupid oversight but still, got me stumped for 3 days.
I Have the same problem, but nothing seems to work for me though.
I'll drop the code from the top down in execution order
jade template
.navbar-right(ng-controller="mvNavBarLoginCtrl")
form.navbar-form
.form-group
input.form-control(placeholder='Email', ng-model='username')
.form-group
input.form-control(type='password', placeholder='password', ng-model='password')
button.btn.btn-primary(ng-click="signIn(username,password)") Sign In
Next step Login controller
angular.module('app').controller('mvNavBarLoginCtrl',function($scope, $http){
$scope.signIn = function (username, password){
console.log('un = ' + username); // Prints fine in the console
console.log('pw = ' + password); // Prints fine in the console
$http.post('/login', {username: username, password: password}).then(function(response){
if(response.data.success){
console.log('Logged in!!');
}
else{
console.log('Failed to log in!!');
}
});
}
});
Next step Route handler
app.post('/login', function(req, res, next){
console.log(req.username); // Already empty
console.log(req.password); // Already empty
console.log(req.body); // Already empty
// Because of the use of AngularJS we can not call passport directly,
// missing req and res will break the code
var auth = passport.authenticate('local', function(err, user){
console.log(user); // prints undefined
if(err){return next(err);}
if(!user){res.send({success:false});}
req.logIn(user, function(err){
if(err){return next(err);}
res.send({success: true, user: user});
});
});
// call the auth function to start authenticate
auth(req, res, next);
});
Next step passport authentication handler
var User = mongoose.model('User');
passport.use(new LocalStrategy({
username: 'username',
password: 'password'
},
function(username, password, done){
console.log("called"); // never printed
// find user based in mongoose schema see 'var User'
User.findOne({userName:username}).exec(function (err,user){
console.log(user) // never printed
if(err){return done(err);}
if(user){
return done(null, user);
}
else{
return done(null, false);
}
});
}
));
passport.serializeUser(function(user, done){
if(user) {
done(null, user._id);
}
});
passport.deserializeUser(function(id, done){
user.findOne({_id:id}).exec(function(err, user){
if(user) {
done(null, user);
}
else{
done(null, false);
}
});
});
There are no errors not in the console and not as node output. I am stumped and read about 5 or so other thread with similar issues, nothing worked.
If somebody could give me the golden tip, I would be eternally gratefull.