Passport.js authenticate failureRedirect with parameters - node.js

Working on Passport.js authentication and want to display messages to client when login is not successful.
My current logic:
app.route('/login').post(passport.authenticate('local', { failureRedirect: '/' }),
(req, res) => {
res.redirect('/profile')
});
Also using similar thing in registeration which is working as I intended using connect-flash to display my message.
app.route('/register')
.post((req, res, next) => {
myDataBase.findOne({ username: req.body.username }, function (err, user) {
if (err) {
next(err);
} else if (user) {
req.flash('message', 'Username is already registered, please try different username');
res.redirect('/');
} else {........
How can I apply similar solution to my login logic? I suppose I need to create a custom callback function but could not figure it out.

Related

NPM passport linkedin login showing 500 if user cancel login

I have implemented npm passport linked social login and it is working fine. But if user cancel the authorisation either they cancel the login on linkedin website. Then it comes back to my website but shows the 500 error.
But as their documentation it should go back to provided failure url. Following my code for failure and success callbacks.
app.get('/auth/linkedin/callback', passport.authenticate('linkedin', {
failureRedirect: '/login'
}), (req, res) => {
//here success login goes.
});
Also attaching the error screenshot.
After doing search for couple of days I found the solution for the issue:
app.get('/auth/linkedin/callback', (req, res, next) => {
passport.authenticate('linkedin', (err, user, info) => {
if (err) {
// failureRedirect
return res.redirect('/signin');
}
if (!user) {
// failureRedirect
return res.redirect('/signin');
}
req.login(user, (err) => {
if (err) {
return next(err);
}
// successRedirect
res.redirect('/profile');
});
})(req, res, next);
});
I think issue in passport-oauth2 module and user_cancelled_login error is not handle. you can delete this module and paste this https://github.com/anuraggu/passport-oauth2.git link package.json file after that install the module

Getting Information from Req.User() into Req.params() in ExpressJS

After people log into my Express app, I'd like to redirect them to a url that reads:
www.mysite.com/:user
What I'm having trouble with is that my req.params object is coming up as an empty object literal when people get re-directed after logging in.
Ideally what I'd like to do is to somehow take the information stored in req.user and pass some of that information into the URL.
So basically I'd like to get from here:
router.post('/login',
passport.authenticate('local', {successRedirect:'/', failureRedirect: '/login', failureFlash: true}));
To here:
router.get('/:user', function(req, res) {
//stuff
}
After logging in the req.user object reads like this:
{
username: joesmith#mail.com,
name: Joe Smith,
password: dkei348#$kDL^583L,
formulas: []
}
And the code I'm attempting to use is as follows:
router.get('/:user', function(req, res) {
var user = req.user.name;
req.params = {
"user": user
}
But this doesn't work because initially req.user.name is undefined if someone isn't already logged in, so I can't get past the console error.
Apparently I don't understand how req.params is generated in enough detail to get around this problem.
Thank you.
If you want to have username in parameters you shoud redirect to '/' + req.user.name); because '/' doesn't have any params. That's why it is undefined. (additionaly you shoud check if parameter is defined and handle the error, so instead of console error you get error 404 or get to next, proper routing path).
Passport Documentation privides examples of doiung it:
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('/' + req.username);
});
or more complex custom callback :
app.get('/login', function(req, res, next) {
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('/' + user.name);
});
})(req, res, next);
});
But I think it is not a good practice and safer would be to redirect to the proper page/content by req.user value without putting it to URL, for example setting req.auth. and then using next(); instead of res.redirect('/' + user.name); to get to the next middleware. There username would be taken from req.auth.username, not from /:username.
How does the structure of your routing looks? You shoud make sure router.get('/:user' .. is not before router.get('/login'...
Looks like you are wanting to access whatever /:user value is. e.g. www.mysite.com/stretch0. Therefore you would access it like var user = req.params.user;
You can provide a custom handler, instead of letting Passport do all the redirecting:
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
req.flash('error', 'Unable to authenticate user');
return res.redirect('/login');
}
if (! user) {
return res.redirect('/login');
}
req.logIn(user, function(err) {
if (err) {
req.flash('error', 'Unable to log in user');
return res.redirect('/login');
}
return res.redirect('/' + user.username);
});
})(req, res, next);
});
This does mean that each logged-in user gets their "personal" URL, because you're redirecting to /USERNAME. I'm not sure from your question if that's actually your intention.

Calling and Saving User Account Custom Data

I'm making a user account system for my new website using node.sdk,stormpath,express.js and passport.js . So I've set up an account with a custom data slot. I would like to know how can I post new data to this custom data slot when they log out and retrieve it when they log in.I'm new to using node and I don't know where to put my code or how to access the 'user' account info when they have logged in. From what I can tell passport.js is handling authentication so I probably can't see the users email to search for their user account url on the stormpath api... maybe I'm missing something here??
router.post('/register', function(req, res) {
var username = req.body.username; var password = req.body.password;
// Grab user fields. if (!username || !password) { return res.render('register', { title: 'Register', error: 'Email and password required.' }); }
// Initialize our Stormpath client. var apiKey = new stormpath.ApiKey( process.env['STORMPATH_API_KEY_ID'], process.env['STORMPATH_API_KEY_SECRET'] ); var spClient = new stormpath.Client({ apiKey: apiKey });
var app = spClient.getApplication(process.env['STORMPATH_APP_HREF'], function(err, app) { if (err) throw err;
account = {
givenName: 'John',
surname: 'Smith',
username: username,
email: username,
password: password,
customData:{
favList:'',
},
};
app.createAccount(account, function (err, createdAccount) {
if (err) {
return res.render('register', {'title': 'Register', error: err.userMessage });
} else {
passport.authenticate('stormpath')(req, res, function () {
return res.redirect('/home');
});
}
});
});
});
// Render the login page. router.get('/login', function(req, res) {
res.render('login', { title: 'Login', error: req.flash('error')[0] }); });
// Authenticate a user. router.post( '/login',
passport.authenticate( 'stormpath', { successRedirect: '/home', failureRedirect: '/login', failureFlash: 'Oops I guess you need an account to get in here..Soz', } ) );
// Render the dashboard page. router.get('/home', function (req, res) { if (!req.user || req.user.status !== 'ENABLED') { return res.redirect('/login'); }
res.render('home', { title: 'Home', user: req.user, } ); });
This is a great question. Thankfully the Passport API has you covered. You want to use a "Custom Callback" function, then you can get access to the user inside of that function. In the case of the Stormpath strategy the user object will be a Stormpath Account instance. However you will need to re-implement some of the redirection logic that you're currently passing in as options. Here is an example of how that would look with the Stormpath strategy:
app.post('/login', function(req, res, next) {
passport.authenticate('stormpath', function(err, user, info) {
if (err) {
return next(err);
}
else if (user) {
console.log('The account is: ', user);
req.logIn(user, function(err) {
if (err) {
next(err);
}else{
res.redirect('/dashboard');
}
});
}else{
req.flash('error',info.message);
res.redirect('/login');
}
})(req, res, next);
});
The docs for this custom strategy can be found here: http://passportjs.org/guide/authenticate/
Another note: I'd suggest creating your spClient outside of the route handler. The Stormpath Client can be used for multiple requests and only needs to be created once per process.

passportjs bearer strategy, load page anyway

I am using passport.js for authentication in my web app. I am following the example given here, that is the following code:
app.get('/api/me',
passport.authenticate('bearer', { session: false }),
function(req, res) {
res.json(req.user);
});
now, the thing is that the code inside function(req, res) is called only with the correct access_token. If the login is wrong the function is never called and it just returns "Unauthorized". Is there a way to execute the function anyway? For example something like this:
app.get('/api/me',
passport.authenticate('bearer', { session: false }),
function(req, res) {
if(req.user){
res.json(req.user);
} else {
res.json({ error: 'whatever' })
}
});
which obviously does not work as the function is never called!
here is a pastie from my code. I would basically like my router to render the page anyway, even with wrong credentials.
From Passport's authenticate page, the authenticate method accepts an optional custom callback function as its third argument.
I haven't tried out with a Bearer strategy, but I don't think it will be any different.
BUT bear in mind that if you this callback function, you have to handle the login process yourself, using res.logIn()
So
app.get('/api/me',
passport.authenticate('bearer', { session: false },
function(err, user,info) {
if (err) { return next(err); } // If there's an error the process
if (!user) { return res.json({ error: 'user not found' }) } // If the user's not found
req.logIn(user, function(err) { // User exists !
if (err) { return next(err); }
return res.json(req.user);
});
});
);
Does that help you ?

Verify access/group in Passport.js

I would like to use passport.js to verify that when users hit certain endpoints that they not only have the correct password but are a member of a specific group or have a certain access.
For simplicity sake if I have access levels of USER and ADMIN.
I can use passport to authenticate a password:
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);
});
}
));
Then with a route I can make sure the user passes auth:
app.get('/api/users',
passport.authenticate('local'),
function(req, res) {
res.json({ ... });
});
But lets say you need to have ADMIN acess to hit /api/users'. Do I need to write my own Strategies? IE do I need to have a local-user, and local-admin strategy, and in each verify the proper access levels?
I think I can do this pretty easily, but the problem arises when I need my site to have different auth methods (maybe sometimes use oauth), I would need to write custom *-user, *-admin strategies for each. Seems like overkill.
Other option is to just verify access/group in each route after the user has been authenticated. But I would prefer to do this in the middle-ware if possible.
Thanks
You could create a simple middleware that checks the group:
var needsGroup = function(group) {
return function(req, res, next) {
if (req.user && req.user.group === group)
next();
else
res.send(401, 'Unauthorized');
};
};
app.get('/api/users',
passport.authenticate('local'),
needsGroup('admin'),
function(req, res) {
...
});
This assumes that the object stored in req.user has a property group. This object is the one passed along from the strategy implementation and deserializeUser.
An alternative could be connect-roles, but I don't know how well that integrates with Passport.
EDIT: you could also combine Passport and the group-checking middleware:
var needsGroup = function(group) {
return [
passport.authenticate('local'),
function(req, res, next) {
if (req.user && req.user.group === group)
next();
else
res.send(401, 'Unauthorized');
}
];
};
app.get('/api/users', needsGroup('admin'), function(req, res) {
});

Resources