I'm an node.js and express.js noob. This question may seems silly but I'm really in confusion.
I'm trying to configure Local Strategry authentication by using passport. As shown in the official documentation, we can figure this Local Strategy by the following code,
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); }
if (!user.verifyPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
My confusion is about the done callback function. When the official docs show this local strategy using as a middleware in the route handler, there is no need to pass the function parameter for this done callback.
app.post('/login',
passport.authenticate('local'),
function(req, res) {
res.redirect('/');
});
So, isn't this done callback function will be null if we don't provide the function parameter? If not, what is that done callback function and what processes will be happening in this done callback function?
done is a method called internally by the strategy implementation.
Then it navigates you, as you can see, to one of the success / error / fail methods (again, by the implementation. there are more options).
Each of these options may calls to the next, where in your snippet code is the following:
function(req, res) {
res.redirect('/');
});
When success is called, it can attach the user to the request or do other things, depending on your needs (it looks for the options you pass to passport.authenticate). If you want to determine when next will be called, you should use custom callback which gives you more flexibility.
I strongly recommend that you read the source.
It's now 2022 and I had the same question. The passport documentation has improved and it describes the done method (also called cb) here: https://www.passportjs.org/concepts/authentication/strategies/#verify-function. You will need to call this yourself in your strategy's verify function.
A verify function yields under one of three conditions: success, failure, or an error.
If the verify function finds a user to which the credential belongs, and that credential is valid, it calls the callback with the authenticating user:
return cb(null, user);
If the credential does not belong to a known user, or is not valid, the verify function calls the callback with false to indicate an authentication failure:
return cb(null, false);
If an error occurs, such as the database not being available, the callback is called with an error, in idiomatic Node.js style:
return cb(err);
Related
I am fairly new to node.js, and haven't done much of javascripts. Tried to search my problem, but couldn't find specific answer related to it.
So, while I was working on attaching the PostgreSQL to my app, I followed a snippet from some example on web, and it seems like working pretty well.
Anyways I wanted to understand how it works, I had a problem understanding specific part of the following code:
module.exports = {
query: function(text, values, cb) {
pool.connect(function(err, client, done) {
if(err) {
return console.error('error fetching client from pool', err);
}
console.log(client);
client.query(text, values, function(err, result) {
done();
cb(err, result);
})
});
}
}
and the specific part is:
pool.connect(function(err, client, done) { ... }
What I understood is connect function takes callback function with err, client, and done as parameter, however I couldn't understand from where the function(err, client, done) is passed to connect function as parameter. By where, I mean an object or a caller that call connect function.
I had suspected that it would be handled internally, but I wanted to know clearly.
Bydefault all callback function, the first parameter must be an error and second will be a result of ur callback function.
Done is similar to callback keyword, which says, your task is over and give response back from where the function has called, its just like return statement in normal function
example:
function callbackDemo(arg1, arg2, callback) {
if (condition)
callback(null, "Success");
else
callback("error");
}
callbackDemo(1, 2, function(err, result){
if(!err)
console(result);
else
console.log(err);
});
We are currently struggling with a Uncaught Error: Can't set headers after they are sent. error message when trying to chain a user sign in into a test with chai-http.
The test signs in as a user which already exists in the database via our API and then should attempts to GET all items from an existing route. Our current test is below which mirrors very closely the example given on the Chai-HTTP documentation http://chaijs.com/plugins/chai-http/#retaining-cookies-with-each-request.
it('should return all notes on /api/notes GET', function (done) {
agent
.post('/users/register')
.send(user)
.then(function() {
return agent
.get('/api/notes')
.end(function (err, res) {
// expectations
done();
});
});
});
Our stack trace
Uncaught Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
at ServerResponse.header (node_modules/express/lib/response.js:718:10)
at ServerResponse.send (node_modules/express/lib/response.js:163:12)
at ServerResponse.json (node_modules/express/lib/response.js:249:15)
at app/routes/usersRouter.js:16:29
at node_modules/passport/lib/middleware/authenticate.js:236:29
at node_modules/passport/lib/http/request.js:51:48
at pass (node_modules/passport/lib/authenticator.js:287:14)
at Authenticator.serializeUser (node_modules/passport/lib/authenticator.js:289:5)
at IncomingMessage.req.login.req.logIn (node_modules/passport/lib/http/request.js:50:29)
at Strategy.strategy.success (node_modules/passport/lib/middleware/authenticate.js:235:13)
at verified (node_modules/passport-local/lib/strategy.js:83:10)
at InternalFieldObject.ondone (node_modules/passport-local-mongoose/lib/passport-local-mongoose.js:149:24)
This is the function being called on our users router which seems to be raising the error (not raised manually, just raised when using chai)
router.post('/register', function(req, res) {
User.register(new User({ username : req.body.username }), req.body.password, function(err, user) {
if (err) {
res.status(500).json({info: err});
}
passport.authenticate('local')(req, res, function () {
res.status(200).json({info: "success"});
});
});
});
Manually testing this functionality works correctly, the issue seems to purely be down to our test and how it is interacting with passport.
Does anyone have any suggestions or pointers which could be of help?
Is there an err object being passed in the User.register callback? If so, try putting return res.status(500).json({info: err}); so that the passport code will not run. The return will exit the function and will not attempt to set the headers twice.
This all comes back to two different pieces of code both answering the request (res.send or res.json).
Essentially there are two possibilities:
1. Passport is using the res object to answer the request, before you do. Check the docs on how this should be done.
2. You get an error and since you have a bug with a missing return in the error handler the res object is set twice.
This is a late answer but I was just having this exact problem.
Did you try putting your passport.authenticate function inside an else statement?
I found that fixed this problem for me.
I am reading a book about NodeJs Connect. There is this small part about basicAuth module. I know that basicAuth is now deprecated, but I cannot understand this simple code. The book says
Providing an asynchronous callback function
The final option is similar, except this time a callback is passed to
basicAuth() with three arguments defined, which enables the use of
asynchronous lookups. This is useful when authenticating from a file
on disk, or when querying from a database.
Listing 7.7. A Connect basicAuth middleware component doing
asynchronous lookups
And no other information. Thats the whole part about having a callback in the basicAuth
So, code gets the username and the password. Then hypothetical object User has a method authendicate that checks if this user actually exists. And when its finished, calls the gotUser function. gotUser contains either a returned error (=no user found with that username/password) or a returned user object (a user found with that username/password). Am I right?
gotUser checks if there is an error. If there is, returns and calls callback with an error argument. So wait, what will callback do at this point? Its not defined anywhere. Will it pass the error to an error handler function? And how?
If there is not an error, gotUser calls callback again with null(= no error) and user. Once again, what will callback do? Why pass the returned user to the callback and not grab its name, mail, age etc etc and use them on a session or fill the innerHTML of a tag or whatever?
Thanks
So wait, what will callback do at this point? Its not defined anywhere.
The value of callback is defined by the basicAuth middleware.
You can find its definition within the basic-auth-connect module, used by connect, in the module's index.js:
callback(user, pass, function(err, user){
if (err || !user) return unauthorized(res, realm);
req.user = req.remoteUser = user;
next();
});
When gotUser() invokes callback(...), it's call the function(err, user){...} from the above snippet, passing the err and/or user along to be used.
And, how they're used, in the two scenarios you were wondering about...
gotUser checks if there is an error. If there is, returns and calls callback with an error argument. So wait, what will callback do at this point?
If there is not an error, gotUser calls callback again with null(= no error) and user. Once again, what will callback do?
The if (err || !user) condition will pass for both (one has an error, the other is lacking a user). It then considers the request unauthorized and will end the response immediately.
function unauthorized(res, realm) {
res.statusCode = 401;
res.setHeader('WWW-Authenticate', 'Basic realm="' + realm + '"');
res.end('Unauthorized');
};
Why pass the returned user to the callback and not grab its name, mail, age etc etc and use them on a session or fill the innerHTML of a tag or whatever?
The middleware is applying separation of concerns, keeping itself as small and concise as possible. It's goal is just to determine a req.user and validate it.
When it's done that successfully, other middleware in the application's queue will be able to reference the user that was found. This can includes using it to render markup from a view:
// determine the user
app.use(connect.basicAuth(...));
// now make use of it
app.use(function (req, res, next) {
viewEngine.render('view', { user: req.user }, function (err, result) {
if (err) return next(err);
res.setHeader('Content-Type', 'text/html');
res.end(result);
});
});
Note: This is generalized and won't run as-is. You'll need to find and setup a view engine of your choice and substitute that into the snippet.
Also, side note on...
fill the innerHTML of a tag
Though Node.js is executing JavaScript, it's doing so within its own environment, completely detached from any browsers. It's not possible to interact directly with the DOM currently seen by the user.
There are a couple of different things going on. For one, app.use expect a function that will be called with req, res, and next. When you run connect.basicAuth, it runs this method.
Since this is a middleware method, this method will run every time a route that was defined after this method is hit.
The second thing that is going on is connect.basicAuth is a function that will be called with username, password, and a callback method. Callback is something that connect.basicAuth provides.
If you return callback(err), it will send a 401 Not Authorized back to the client. If you return callback(null, user), it will continue until either the next middleware function, or the appropriate route.
I'm trying to learn Express session and authentication handling.
For example:
app.post('/login', authCredentials, function(req, res) {
console.log("second")
});
function authCredentials(req, res, next) {
//this happens first
console.log(req.body) // => { username: etc, password: etc }
next();
}
My question is just how much should my authCredentials function do?
For example if the credentials are correct, I can do something like
res.redirect('/index'). Once I do that, however, what purpose does the second function have?
Other questions:
How would I handle invalid credentials?
If I make authCredentials just return true or false depending on the credentials, doesn't that break the middleware flow because it would never invoke next()?
Is it possible to access anything in authCredentials in the anonymous callback after it? Basically in the function(req, res) { }?
The answer depends on your authentication strategy i.e. are you using session identifiers, access tokens, etc.
In either case I suggest that you break out the credential exchange (aka login) from the authentication.
function usernamePasswordExchange(req,res,next){
var username = req.body.username;
var password = req.body.password;
callToAuthService(username,password,function(err,user){
if(err){
next(err); // bad password, user doesn’t exist, etc
}else{
/*
this part depends on your application. do you use
sessions or access tokens? you need to send the user
something that they can use for authentication on
subsequent requests
*/
res.end(/* send something */);
}
});
}
function authenticate(req,res,next){
/*
read the cookie, access token, etc.
verify that it is legit and then find
the user that it’s associated with
*/
validateRequestAndGetUser(req,function(err,user){
if(err){
next(err); // session expired, tampered, revoked
}else{
req.user = user;
next();
}
});
}
app.post('/login',usernamePasswordExchange);
app.get('/protected-resource',authenticate,function(req,res,next){
/*
If we are here we know the user is authenticated and we
can know who the user is by referencing req.user
*/
});
Disclaimer: I work at Stormpath and we spend a lot of time writing
authentication code :) I just wrote our newest library, stormpath-sdk-express,
which has a concrete implementation of my suggestions
You want to add your authCredentials middleware to every end point that needs authentication. app.post('/login') usually does not need any as you want to access this end point to actually get credentials in the first place.
When credentials are correct/valid you simply invoke next() and the workflow will jump to the next middleware or the actual end point. If there was an error, invoke next() with an error object like next(new Error('could not authenticate'); for instance. Add an error route to your general routing and the error will be handled there:
app.use(function(err, req, res, next) {
res.render('error', err);
});
Should be answered by now.
A middleware does not return a value. It either calls next() or ends the process differently by calling res.send().
There are different approaches to pass variables from one middleware to another. The most common is probably to attach the desired value to the req parameter.
authenticate is an asychronous function in the following example:
function authCredentials(req, res, next) {
authenticate(req.body, function(err, user) {
if (err) {
return next(err);
}
req.user = user;
next();
});
}
I'm writing my first (non tutorial) node application and am at a point where I'm writing a function that should take the username and password as parameters and query them against the user table of my database to return either true or false. The database is setup, and the app is connecting to it successfully.
However, I haven't worked with SQL very much, nor node, and I'm unsure how to proceed with this function (and short surrounding script). Here it is:
console.log('validator module initialized');
var login = require("./db_connect");
function validate(username, password){
connection.connect();
console.log('Connection with the officeball MySQL database openned...');
connection.query(' //SQL query ', function(err, rows, fields) {
//code to execute
});
connection.end();
console.log('...Connection with the officeball MySQL database closed.');
if(){ //not exactly sure how this should be set up
return true;
}
else{ //not exactly sure how this should be set up
return false;
}
}
exports.validate = validate;
This is using node-mysql. I'm looking for a basic example of how I might set the query and validation up.
I think you'll want to rethink your app into a more node-like way (i.e. one that recognizes that many/most things happen asynchronously, so you're not usually "returning" from a function like this, but doing a callback from it. Not sure what you plan to get from node-mysql, but I would probably just use the plain mysql module. The following code is still most likely not entirely what you want, but will hopefully get you thinking about it correctly.
Note that the use of 'return' below is not actually returning a result (the callback itself should not return anything, and thus its like returning undefined. The return statements are there so you exit the function, which saves a lot of tedious if/else blocks.
Hope this helps, but I'd suggest looking at various node projects on github to get a better feel for the asynchronous nature of writing for node.
function validate(username, password, callback){
var connection = mysql.createConnection({ user:'foo',
password: 'bar',
database: 'test',
host:'127.0.0.1'});
connection.connect(function (err){
if (err) return callback(new Error('Failed to connect'), null);
// if no error, you can do things now.
connection.query('select username,password from usertable where username=?',
username,
function(err,rows,fields) {
// we are done with the connection at this point), so can close it
connection.end();
// here is where you process results
if (err)
return callback(new Error ('Error while performing query'), null);
if (rows.length !== 1)
return callback(new Error ('Failed to find exactly one user'), null);
// test the password you provided against the one in the DB.
// note this is terrible practice - you should not store in the
// passwords in the clear, obviously. You should store a hash,
// but this is trying to get you on the right general path
if (rows[0].password === password) {
// you would probably want a more useful callback result than
// just returning the username, but again - an example
return callback(null, rows[0].username);
} else {
return callback(new Error ('Bad Password'), null);
}
});
});
};