Passport.js authentication with node.js - javascript

I am from laravel background trying to implement passport.js authentication in my sails.js app
the documentation is minimal and also hard to understand
Here is my login.js
module.exports = {
/*
*Normal login
*/
login:function (req,res) {
//user input
console.log('email'+req.parm('email')+'password'+req.param('password'))
passport.authenticate(
'local-login',
function (req,res) {
}
}
passport.use('local-login',new LocalStrategy(function (username,password,done) {
if(username=='test')
return done(null,username);
else
return done(null,false,{message:'Invalid userinfo'})
}));
but the passport.authenticate never fired
From their documentation
app.post('/login',
passport.authenticate('local'),
function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
res.redirect('/users/' + req.user.username);
});
also what is the meaning of this If this function gets called, authentication was successful.
Found this tutorial http://iliketomatoes.com/implement-passport-js-authentication-with-sails-js-0-10-2/ but its explanation so poor

The tutorial is pretty old as it's for sails 0.10, but it is still valid. You are using the passport-local strategy. When you define your strategy you've got an extra parameter. Remove this 'local-login' parameter.
You currently have:
passport.use('local-login',new LocalStrategy(function...
Replace the above with:
passport.use(new LocalStrategy(function...
Then when you call authenticate specify 'local' not 'local-login' as the strategy, so you have:
passport.authenticate(
'local',
function (req,res)...
'local' goes with passport-local. If you we're using the passport-http-bearer strategy then you would call
passport.authenticate('bearer', function...
I usually put my strategy definitions in /config/bootstrap.js along with the session serialization and helpers for finding the user. Then my controller-->service makes the passport.authenticate call.

Related

can /path/{?} be used in path in nodejs?

I am relatively new to node.js and trying to write a route which will check the authorization of all the users if the mentioned endpoint starts with /api.
I read that for optional value ? can be used {_id?} like this but is it possible to use it like {?}.
and How do I call this route into another route which actually does the job of GET method?
Currently the method looks like this
server.route({
method: 'GET',
path: '/api/something/nothing/{_id?}',
handler: function (request, reply) {
Controller.vcontroller.get(request.headers.authorization, request.params, function (err, success) {
console.log(request.headers);
console.log(request.headers.authorization);
if (err) {
reply(func.sendError(err));
} else {
reply(func.sendSuccess(APP_CONSTANTS.STATUS_MSG.SUCCESS.DEFAULT, success)).code(200);
}
});
},
config: {
description: 'desc',
tags: ['api', 'order'],
validate: {
headers: func.authorizationHeaderObj,
params: {
order_id: Joi.string().required().trim(),
_id: Joi.string().optional().trim()
},
failAction: func.failActionFunction
},
plugins: {
'hapi-swagger': {
responseMessages: APP_CONSTANTS.swaggerDefaultResponseMessages
}
}
}
}
});
when I pass endpoint /api it should check the authorization for all the users for GET PUT POST & DELETE respectively.
In other words I want global authorisation which is route specific
Can you suggest a way to implement it?
To check if all requests to endpoints starting with /api are authorised you can use middleware, i.e.
app.use('/api', (req, res, next) => {
// this uses passport.js for auth, you could use something else
if(req.isAuthenticated()) {
return next();
}else{
return res.status(401).send();
}
});
I'm not entirely clear that I'm understanding your question, so I'll restate what I think you're asking and then answer. If I am not understanding, please clarify.
What I think you're asking is whether you can run a check anytime someone hits a URL path that starts with /api, probably for user authorization purposes.
The answer is, yes, you can just incorporate that into a middleware (though I strongly recommend Passport for all your authentication needs.
That said, if you're using Express, then you can just add middleware at the start of your routing like so:
app.use('/api', (req, res, next) => {
// trivial implementation, not for production
const users = ['bob', 'mari', 'hasan'];
if (users.indexOf(req.user) >= 0) {
// user is authorized
return next();
}
// Forbidden
return res.sendStatus(403);
});
Put that before your other routes, and any route starting with /api will pass through this first. Obviously, I'm assuming you have populated req.user here somehow, but if you're using Passport as I suggested that will be done for you.

Passport-Google-OAuth Callback Not working when used in Web Service

I Have used Passport-Google-OAuth in Node.js web service project. I am using OAuth2Strategy.
The process i have used is i call the web service method to authenticate user from his Gmail account. Initially i serve the Raw HTMl which i receive from calling the Passport-google-OAuth. Which works fine.
Then i login with valid Gmail accounts. Once the Callback Url is called by google the server goes into infinite loop and calls the callback url again and again after fixed interval of time.
My Passport strategy configuration for Google is like this:
// Use the GoogleStrategy within Passport.
// Strategies in Passport require a `verify` function, which accept
// credentials (in this case, an accessToken, refreshToken, and Google
// profile), and invoke a callback with a user object.
passport.use(new GoogleStrategy({
clientID : "948630708036-2t6mestiv81gtv0s9n6iptoava4o1cpa.apps.googleusercontent.com",
clientSecret : "omugRnr7nad2yMmefiZdBaLL",
callbackURL : "http://localhost:4000/api/auth/google/callback"
},
function(token, refreshToken, profile, done) {
console.log('Inside global callback.');
// make the code asynchronous
// User.findOne won't fire until we have all our data back from Google
process.nextTick(function() {
// try to find the user based on their google id
User.findOne({ 'google.id' : profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
// if a user is found, log them in
return done(null, user);
} else {
// if the user isnt in our database, create a new user
var newUser = new User();
// set all of the relevant information
newUser.google.id = profile.id;
newUser.google.token = token;
newUser.google.name = profile.displayName;
newUser.google.email = profile.emails[0].value; // pull the first email
return done(null, newUser);
}
});
});
}));
Then i am calling the Passport from the endpoint in the service project:
passport.authenticate('google', { session:false,scope : ['profile', 'email'] });
And the Callback URL contains the following code where i am sending the returned Google account details of the user in JSON format to the client which accessed the web service intially.
function(req, res) {
console.log('Callback by Google:'+res.body+' || '+ res.headers);
console.log('Response Object:'+util.inspect(res));
passport.authenticate('google', { session : false }),function(req,res){
console.log('Callback authenticated.User: +req.user);
res.json(req.user);
}
In the Log i am getting "Callback by Google: undefined || undefined".
I am disabling sessions since this will be the API Server feeding data to various clients.
I dont know what mistake i am doing. Kindly point out any resource or example where the Passport-Google-OAuth(OAuth2Strategy) is used in a API(Web Service) server. Do i need to follow some other way. Thanks for ur help in advance.
There may be a problem in your routes. Look at the tutorial here
https://scotch.io/tutorials/easy-node-authentication-google
It's the best I have seen. And I have implemented something similar.

How can I impersonate another user with Passport.js in Node?

Using Passport.js in Node, is there a way for me to allow one user to impersonate another? eg. as an Administrator in the application, I want to be able to log in as another user, without knowing their password.
Most simply, I would be satisfied if I could change the serialized user data (user ID) so when deserializeUser is called it will just assume the identity of the alternate user. I've tried replacing the value at req._passport.session.user and the value at req.session.passport.user but the net effect is just that my session seems to become invalid and Passport logs me out.
Passport provides a req.logIn method in case you want to do the authentication manually. You can use it to login any user even regardless of authentication.
Here's how you can use it. Have the Admin login normally, who'll have an isAdmin flag set.
Then place a middleware before passport.authenticate in your login route. This will login the new user based only on their username, if the currently logged in user isAdmin.
app.post('/login',
function forceLogin(req, res, next) {
if (!req.user.isAdmin) return next(); // skip if not admin
User.findOne({
username: req.body.username // < entered username
}, function(err, user) {
// no checking for password
req.logIn(user);
res.redirect('/users/' + user.username);
});
},
passport.authenticate('local'),
function(req, res) {
res.redirect('/users/' + req.user.username);
}
);
I have another way to impersonate, because:
I didn't want to mess with internals of authentication/passport like
session storage / logIn / etc. You must understand them really well
and also they are prone to change so I'd say it's not an option for
me.
Also, I'd like to still be able to tell if action is made from
superuser (impersonated) or normal user (not impersonated).
What I do is:
Have a route for user with superadmin role to impersonate, like /superadmin/impersonate?username=normaluser1 which sets req.user.impersonated.userid = normaluser1.userid
Then I have a middleware, which checks if user is superadmin and is impersonated:
if (req.user.isAdmin && req.user.impersonated) {
req.user.userid = req.user.impersonated.userid;
}
Also, I have found this to be a good article about user impersonation. Similar to my approach, and good for inspiration for building something similar.
The answer to your question is basically: no. The reason is this: the sessions library that is being used 99% of the time is signing the cookies, so if you tamper with the data the web server will reject it.
The way around this is to write your own passport authentication strategy that obviously doesn't do this, but I'm assuming you're talking about working with the built-in strategies here.

Express user authentication middleware, how much should it do?

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();
});
}

Node.js preresponse with Express

So I'm doing a web page with Node.js and Express framework. I already have registration and login (I'm holding users id in a session). Next step is to render different page whenever a user is authenticated.
Some of those pages require a User object which is just a mapping of a user from my db. So whenever an authenticated request comes I need to retrieve the user from my db. But writing this code every time seems to be a bad way to do this. So here's the question: is it possible (and if it, then how?) to do, say preresponse, so I can automaticaly retrieve User object whenever I know that the user is authenticated and THEN do the main response?
Middleware is what you are referring to. Middleware is just a function that gets called sequentially when the route is triggered. So to have a loadUser function:
function loadUser(req, res, next) {
// You would fetch your user from the db
var user = users[req.params.id];
if (user) {
req.user = user;
next();
} else {
next(new Error('Failed to load user ' + req.params.id));
}
}
app.get('/user/:id', loadUser, function(req, res){
res.send('Viewing user ' + req.user.name);
});
You can define as many middleware functions as your need. Just be sure to call next() at the end to pass the route handling on to the next function.
This EXACT example is covered in the express.js route middleware docs. Go read it and you'll see the pattern of using middleware to factor out common functionality that you need at many route paths in your app.

Categories

Resources