I'm relatively new to using passport and am currently trying to implement passport-http for user authentication on my node.js api. (Previously used jwt tokens with no problems).
It's not clear to me what passport-http should be doing. Right now I have a route for registration that looks like this:
routes/user.js
router.post('/', sanitize, validate, function(req, res, next) {
const user = new User({
username: req.body.username,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, config.secret_num)
});
//Check if e-mail or username already exists
const userExistsPromise = User.findOne({username: user.username});
const emailExistsPromise = User.findOne({email: user.email});
Promise.all([userExistsPromise, emailExistsPromise]).then(function(docs) {
if(docs[0]) { //If we find a doc where username matches
return sendJsonResponse(res, false, "This username already exists.", 409);
}
if(docs[1]) { //If we find a doc where email matches
return sendJsonResponse(res, false, "This email address already exists.", 409);
}
user.save(function(err) {
if(err) {
console.log(err);
return sendJsonResponse(res, false, "There was an error processing your request.", 400);
}
return sendJsonResponse(res, true, "Successfully registered user.");
});
}, function(err) {
console.log(err);
return sendJsonResponse(res, false, "There was an error processing your request.", 400);
});
});
This simply adds a username, e-mail and password to the db. My first question is do I need to do this via passport somehow?
My current passport middleware is defined as follows:
middleware/auth.js
// Load required packages
const passport = require('passport');
const BasicStrategy = require('passport-http').BasicStrategy;
const User = require('../models/user');
passport.use(new BasicStrategy(
function(username, password, callback) {
User.findOne({ username: username }, function (err, user) {
if (err) { return callback(err); }
// No user found with that username
if (!user) { return callback(null, false); }
// Make sure the password is correct
user.verifyPassword(password, function(err, isMatch) {
if (err) { return callback(err); }
// Password did not match
if (!isMatch) { return callback(null, false); }
// Success
return callback(null, user);
});
});
}
));
exports.isAuthenticated = passport.authenticate('basic', { session : false });
And I have a test route that looks like this:
const auth = require('../middleware/auth');
router.get('/test', auth.isAuthenticated, function(req, res, next) {
return sendJsonResponse(res, true, "This is a test get only for authenticated users");
});
This works fine when I pass a valid/invalid username and password as a Basic Auth using Postman. So I correctly get "invalid credentials" when credentials are invalid, and I get "This is a test get only for authenticated users" when I have valid credentials.
Great, except how would I have the login credentials in my Basic Auth header in the first place?
I have a login route like this:
router.get('/', auth.isAuthenticated, function(req, res, next) {
return res.json(req.user);
});
But this doesn't look right because I'm sending back a username, email, and hashed password... so 1) This is probably not a good idea. 2) This won't even work because I can't just put the username/pass in the header for the next request.
Shouldn't I send some kind of header or cookie or session that'll tell me on the next request that the user has valid credentials or invalid credentials? I don't understand how to fill in this gap.
Edit: So as I wrote this question, and thought about it, I think I might have been over-complicating it in my head. Seems like the intuitive way is to store the credentials in a cookie or local storage on the client side and use basic auth header every time I make a request that requires credentials... does that sound about right?
Still unsure if passing credentials via basic auth like this is secure though.
via snanda