I am making an android app in partnership with a colleague, he is an Android developer and I know very little about android dev. I do the backend stuff, I made the login and auth using node.js, express, and passport.js.
I hosted the server locally and used postman to check the auth and registration processes, all were working fine. I am getting the status codes my friend wanted for his Front-end. In the authentication part using passport.js when success I am passing req.user which should return the user body, so that my friend on the Front-end can use the field user.firstName from user object to display a welcome message.
Through Postman, the user body is getting defined and I am getting a user object with all fields in the Postman window, but through the app it is giving an error.
firstName is undefined property.
Passport.js logic:
const LocalStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
//load user model
const User = require('../models/UserSchema');
module.exports = function(passport){
passport.use(
new LocalStrategy({usernameField: 'roll'}, (roll, password, done) => {
//find user
User.findOne({roll: roll})
.then(user =>{
if(!user){
return done(null, false, {message: 'Roll number not registered'});
}
//match password
bcrypt.compare(password, user.password, (err, isMatch) =>{
if(err) throw err;
if(isMatch){
return done(null, user);
}else{
return done(null, false, {message: 'Password incorrect'});
}
})
})
.catch(err => console.log(err));
})
);
/*passport.serializeUser( function(id, done) {
done(null, User.roll);
});
passport.deserializeUser(function(id, done){
User.findById(roll, function(err, user){
done(err, user);
});
});*/
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser((_id, done) => {
User.findById( _id, (err, user) => {
if(err){
done(null, false, {error:err});
} else {
done(null, user);
}
});
});
}
Login Route:
//Login Handle
router.post('/login', (req, res, next) =>{
console.log('/user/login')
passport.authenticate('local', {
successRedirect: '/success',
failureRedirect: '/failure',
session: true,
failureFlash: false
})(req, res, next);
//res.json(pass.user.name);
});
/success route:
router.get('/success', (req, res) => {
console.log(req);
let message = 'Login Succesful';
//let user = req.user.firstName
res.status(200).json({'message':message, 'user': req.user.firstName});
})
I guess you are also using body-parser or express.json() to parse the incoming body request to JSON. If this is the case you should send the response back like this:
req.body.user.firstName
For POST requests: req.body
For GET parameters: req.params
For GET query strings: req.query
Related
Assuming I have required passport, bcrypt, express-sessions and mysql correctly this code is supposed to add the user info to the session. I cannot for the life of me work out where it is going wrong.
App.js file
passport.use('local', new LocalStrategy({
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true //passback entire req to call back
}, function(req, email, password, done) {
connection.query("SELECT * FROM accounts WHERE email = ?", [email], async(err, rows, fields) => {
//if an error occurrs in mysql
if (err) {
return done(null, false)
connection.end()
}
//if there are no matching entries
if (!rows.length) {
console.log('invalid email')
return done(null, false)
connection.end()
}
//if the passwords don't compare
if (!(await bcrypt.compare(password, rows[0].password))) {
console.log('incorrect password')
done(null, false)
connection.end()
}
//if none of that happens
req.session.user = rows[0]
console.log('logged in')
connection.end()
});
}));
//handles de/serialization of the user data (all integrated from passport docs)
passport.serializeUser(function(user, done) {
return done(null, user.id)
console.log(user.id + "serialized")
});
passport.deserializeUser(function(id, done) {
connection.query("SELECT * FROM accounts WHERE id = " + id, function(err, rows) {
console.log('done' + rows[0])
return done(err, rows[0])
});
});
Auth route code
router.post('/auth', passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/account'
}));
The code logs the user in, which is logged in the console, then logs them out again with a failure redirect to /account. I don't know where the authentication is going wrong, thanks for any replies in advance!
You can achieve the same using express-session..
install express-session: npm i express-session --save
Require it in your node application: var session = require('express-session');
Configure: app.use(session({ secret: "YourSecretKeyGoesHere", saveUninitialized: true, resave: true }));
And then check your session..
I've a use-case. My application has multiple users where not all users have the access to all the functionalities in the application. I have to restrict them from accessing the application. For that, I've been writing logic that works as the gateway.
I've created different rules which provides a different kind of authentication methods.
When a user log in to the application, will generate a JWT token upon successful login. That token will be authenticated using the rules given.
Here's my code.
server.js
global.app = new require("express")();
global.passport = require("passport");
require("./bin/kernal");
require('./bin/passport');
----Remaining Code----
TokenAuth.js
var passport = require("passport");
require("../../bin/passport");
module.exports= function (req, res, next) {
passport.authenticate('jwt', function (error, user) {
console.log(user);
if (error) return next(error);
if (!user) return res.status(401).json({"error":"Incorrect data", "status":401, "success":false});
//req.user = user;
next();
})(req, res, next);
};
module.exports.UserAuth = function(req, res, next){ // Error Web Response
passport.authenticate('user_rule', function (error, user) {
if (error) return next(error);
if (!user) return res.status(500).json({"message":"No User found", "status":500, "success":false});
//req.user = user;
next();
})(req, res, next);
};
Passport.js
var passport = require("passport");
app.use(passport.initialize());
app.use(passport.session());
require('../app/middlewares/TokenAuth')
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findOne({_id: id}, function (err, user) {
done(err, user);
});
});
var JwtStrategy = require('passport-jwt').Strategy;
var ExtractJwt = require('passport-jwt').ExtractJwt;
var options = {};
options.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
options.secretOrKey = process.env.jwt_secret;
passport.use(new JwtStrategy(options, function (payload, done) {
console.log(payload)
User.findOne({_id: payload._id}, function (error, user) {
if (error) return done(error, false);
if (!user) return done(null, false);
// req.auth_user = {"_id":user._id,"email":user.email,"name":user.name,"status":user.status}
done(null, user);
});
}));
passport.use('user_rule', // UserAuth in TokenAuth.js has to use this functionality
new JwtStrategy(options,async function (payload, done) {
console.log(payload)
let err, authUser,companyResource;
[err,authUser] = await to(CompanyContacts.findById(payload._id).populate('company',
["accountid","company_name","email","status"]).lean().exec());
if (err) return done(err, false);
if (!authUser) return done(null, false);
let user= authUser;
if(user.status==true && user.company.status==true){
req.auth_user = {"_id":user._id,"email":user.email,"name":user.fullname,status:user.status,isPrimary:user.primarycontact};
req.auth_company=user.company._id;
req.isAdmin=false;
req.auth_role=user.role;
done(null, user);
}else{
return done(err, false);
}
})
);
user_api.js
router.get("/all/menus",TokenAuth,MenuController.getAllDropDowns);
router.post("/company/user/signin", TokenAuth.UserAuth, AuthController.customerlogin);
Here, when the post api get executed, only the user who gets authenticated has to get the access that api.
But the problem here is, whenever I use this authentication methods, I'm getting the error specified below.
{
"error": "Incorrect data",
"status": 401,
"success": false
}
As per my knowledge, the data is not going into the Passport.js file to get authenticate.
Is this approach good, or do I need to make any changes in this code to make it work?
I am using passport with local strategy .but I want to send message and status when credential is not match or (user is not exit is DB)
here is code
router.js
const passport = require('passport');
const passportConfig = require('../passport')
const passportSignIn = passport.authenticate('local', { session: false });
router.route('/login',)
.post(passportSignIn,controller.login)
on controller file
login: async (req, res, next) => {
console.log(req.body);
res.json({status:200})
}
passport.js
passport.use(new LocalStrategy({
usernameField: 'email'
}, async (email, password, done) => {
const user = await db.User.findOne({where: {email: email}});
if (!user) {
return done(null, false,{message:"No user exit"});
}
const isMatch = await bcrypt.compare(password, user.dataValues.password);
console.log(isMatch, 'isMatch');
if (!isMatch) {
return done(null, false);
}
// Otherwise, return the user
done(null, user);
}))
Client code
when user click on login button it goes to /login path first it goes to passportSignIn function or below function.
`new LocalStrategy({
usernameField: 'email'
}, async (email, password, done) => {`
now if user not found I want to send this message on the client as the response ("No user exit")
return done(null, false,{message:"No user exit"});
You have to update your login controller, like so:
login: (req, res, next) => {
console.log(req.body);
passport.authenticate('yourStrategy', function(err, user, info) {
if (err) {
return res.status(500).json("Internal Server Error");
}
if (!user) {
// This 'info' variable below would be - { message: "No user exit" }
// as you passed in the done() callback as the third param
return res.status(404).json(info.message);
}
}
}
I got below express node.js server code using Passport. At it my whole routes definition depends upon a MongoDB connection using mongo-db but model used by Passport is done through another connection by mongoose. I mention these two details cause I think it should also be coded in a better way.
However, the main problem is that even though Passport it's doing it's work, I still can go to localhost/registro directly no matter I didn't logged in first.
When someone tried to access to localhost/registro it should be redirected to start page if a login and authentication wasn't done first.
I care about a safe implementation of it, I'd also like to have some information about the user during the session time.
I'm quite confused about what I should try, cookies, sessions, etc. Apart that in new express version middlewares work different than before.
This is my server.js:
var express = require('express')
var mongodb = require('mongodb')
var mongoose = require('mongoose')
var bodyParser = require('body-parser')
var passport = require('passport')
var LocalStrategy = require('passport-local').Strategy;
var app = express()
var BSON = mongodb.BSONPure
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(__dirname+"/public"))
app.use(bodyParser())
var MongoDBClient = mongodb.MongoClient
mongoose.connect('mongodb://localhost/psicologosTuxtepecDB')
var Schema = mongoose.Schema
var userCredential = new Schema({
username: String,
password: String
}, {
collection: 'members'
})
var userCredentials = mongoose.model('members', userCredential)
passport.serializeUser(function(user, done) {
done(null, user);
})
passport.deserializeUser(function(user, done) {
done(null, user);
})
passport.use(new LocalStrategy(function(username, password, done) {
process.nextTick(function() {
userCredentials.findOne({
'username': 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);
});
});
}));
MongoDBClient.connect("mongodb://localhost/psicologosTuxtepecDB", function (error, psicologosTuxtepecDB) {
if (error) {
console.log("We've got a connection error, so far we should take this function better for a correct debug")
}
else {
console.log("Connection to psicologosTuxtepecDB has been successful")
// Seleccionamos una colección
var psicologosCollection = psicologosTuxtepecDB.collection("psicologos")
app.get('/registro', function(request,response) {
response.sendfile("public/html/registro.html")
})
// Cuando nos hagan una petición HTTP de tipo POST en la ruta psicologos...
app.post("/psychos", function(request, response) {
var psychologist = {
personalData: request.body._personalData,
professionalData: request.body._professionalData,
professionalInterests: request.body._professionalInterests
}
psicologosCollection.insert(psychologist, function(error, responseFromDB) {
if (error) {response.send(responseFromDB)}
console.log("Se ha insertado: "+ JSON.strinfigy(responseFromDB))
response.send(responseFromDB)
})
})
app.get("/psychos/:id", function(request, response) {
var id = new BSON.ObjectID(peticion.params.id)
psicologosCollection.findOne(
{'_id':id},
function(error,responseFromDB) { if (error) {response.send(responseFromDB)} response.send(responseFromDB)}
)
})
app.get("/psychos", function(request,response) {
psicologosCollection.find().toArray(function(error,responseFromDB) {
if (error) {response.send(responseFromDB)}
response.send(responseFromDB)
})
})
app.post('/login',
passport.authenticate('local', {
successRedirect: '/loginSuccess',
failureRedirect: '/loginFailure'
})
)
app.get('/loginFailure', function(req, res, next) {
res.redirect('/')
})
app.get('registro', function(request, response) {
response.sendfile('public/html/registro.html')
})
app.get('/loginSuccess', function(req, res, next) {
res.redirect('/registro')
})
app.listen(80, function () {
console.log("app escuchando en el puerto Maricela fecha de nacimiento DDMM")
})
}
})
These are my Passport statements:
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done) {
done(null, user);
})
passport.deserializeUser(function(user, done) {
done(null, user);
})
passport.use(new LocalStrategy(function(username, password, done) {
process.nextTick(function() {
userCredentials.findOne({
'username': 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);
});
});
}));
Express "chains" route methods. The basic idea behind securing routes in Express.js is to have a method that checks the a&a before allowing the request to proceed to the intended route. There are a few ways to do this:
Method 1: Add the auth method to the route declaration
function requireAuth(req,res,next){
if user is authenticated
next();
else
res.send(401);
}
app.get('/registro', requireAuth, function(request, response) {
response.sendfile('public/html/registro.html')
})
Method 2: Declare a route handler for your auth
app.get('/registro', function(req,res,next){
if user is authenticated
next();
else
res.send(401);
})
app.get('/registro', function(request, response) {
response.sendfile('public/html/registro.html')
})
Method 3: Use app.use() instead of a verb
With this method, you need to consider when app.router gets inserted into the middle-ware.
Edit 1: Where would the require auth method be declared
If you plan on placing route handlers in multiple .js files, it's a good idea to put your require auth mehtod in a separate .js file as well and require it where appropriate.
Otherwise, you can just stick it in the same file with everything else.
Edit 2: How do sessions work in Express.js and Passport.js
From the Passport.js documentation, you first need to configure the express session before the passport session:
app.use(express.session({ secret: 'keyboard cat' }));
app.use(passport.initialize());
app.use(passport.session());
Note: You should probably consider using something other than the memory store for session management.
Along with the serializeUser and deserializeUser methods, at this point Passport will have placed a .user on the request.
You can also use req.isAuthenticated() to determine if the user is authenticated.
Note 2: I've had problems getting the serializeUser and deserializeUser methods to work with Passport-Saml. If that is the case, just manage the session yourself.
Couple of questions. I set up authentication in my app using the following code:
passport.use(new LocalStrategy(function(username, password, done){
Users.findOne({ username : username},function(err,user){
if(err) { return done(err); }
if(!user){
return done(null, false, { message: 'Incorrect username' });
}
hash( password, user.salt, function (err, hash) {
if (err) { return done(err); }
if (hash == user.hash) return done(null, user);
done(null, false, { message: 'Incorrect password' });
});
});
}));
app.get('/admin', function (req, res){
res.render('login.jade');
});
app.post('/admin', function (req, res){
passport.authenticate('local', { successRedirect: '/main',
failureRedirect: '/login',
failureFlash: true });
});
Users is a DB schema that includes username, password, and hash.
The first and most obvious question is, how do I add a new user to the database? I specifically don't want a sign-up page but want to manually add every new user. Is there a way to do this manually?
Next, how do I modify my existing routes to only work if the user is authenticated? For example, I have:
app.get('/comment/:commentID', admin.renderComment);
The above renderCommit is a large handler function but accessing this page should only work if the user is authenticated. How do I check that?
Creating a new user should be relatively straightforward, from a standalone script for instance:
// Load your models, set up database connection, etc.
...
// Create a new user:
Users.create({
username : USERNAME,
password : HASHED_PASSWORD,
salt : GENERATED_SALT,
}, function(err, user) {
if (err) {
console.error('Error creating user:', err.message);
} else {
console.log('User created successfully');
}
});
As for making sure that a user is logged in when certain routes are requested, you can use a simple middleware for that:
app.get('/comment/:commentID', ensureAuthenticated, admin.renderComment);