passportjs and backbone: authenticating users - backbone.js

Currently I been using a chrome app called Postman to test my services from nodejs/express/passportjs.
Currently I'm having trouble wrapping my head around how I should grab the user info and authenticate it with backbone.
I would try to authenticate the user like so:
$.post("http://localhost:3000/login", { username: "joe", password: "pass" })
.done(function(data) {
console.log(data)
//try to pull a service that's protected by passport
})
.fail(function(data) {
console.log(data)
})
Which is not working at all when it's successful. Its giving the 500 error I set for when someone isn't logged in.
Any particular direction I should be going in to manage authentication with passportjs in backbone?

The 500 error means some part of the code in the server is not working properly.
You can send the logged in user from express using passport. You can follow the following example.
var app = express();
var login = require('./routes/login');
app.post('/login',
passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login',
failureFlash: true }),
login.login);
where your login.js file may look like this
exports.login = function (req, res) {
res.json(req.user);
}
the authenticate process of passport populates user variable in request (req) with the logged in user.
Please note, you have to use cookie parser and session of express to make the passport session working. e.g.,
app.use(express.cookieParser());
app.use(express.session({ secret: 'keyboard cat' }));
your local authentication may look like the following (say you have a function that finds user by username (findByUsername)).
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
},
function(username, password, done) {
// asynchronous verification, for effect...
process.nextTick(function () {
// Find the user by username. If there is no user with the given
// username, or the password is not correct, set the user to `false` to
// indicate failure and set a flash message. Otherwise, return the
// authenticated `user`.
findByUsername(username, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
if (user.password != password) { return done(null, false, { message: 'Invalid password' }); }
return done(null, user);
})
});
}
));

Related

Angularjs : server side templating

I am very new to MEAN. And I have made an application using node.js, express and mongodb. I want to send username to dashboard after user is logged in. How can I do it using Angularjs. I don't want to use ejs templating engine. If any Middle ware is required....plzz tell me.
thank you...
this is my usercrud.js
var User = require("../../schema/user/userschema");
var bcrypt = require('bcrypt');
const userOperation={
login(userObject,response){
var username=userObject.userid;
var psw = userObject.password;
User.find({ userid:username}, function (err, user) {
if (err) {
return done(err); }
if (!user) {
return done(null, false, { message: 'no user found' });
}
if(user){
console.log("user's true password is: "+user[0].password);
console.log("password"+psw);
bcrypt.compare(psw, user[0].password, function(err, res) {
if (err){
throw err;}
if(!res) {
console.log('Ooops!. Wrong Pass!');
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
}
if(res){
response.redirect('dashboard');
}
});
}
});
},
}
how can I send username to the dashboard.html
this is userroute.js
router.get('/dashboard',(req,response)=>{
});
As you are using MEAN stack for your application, what you can do is check login via async call and return user object in response. Then you can store that user into localstorage.
Once user is successful in logIn and you get this "user" object in response, redirect user from login to dashboard using angular redirection not from back-end server.
After redirection use localstorge for getting user information.

How to use the session from passportjs

I am able to login using passport-local. I want to test if the session created by passport is valid. I am logging in from Angular. When the user logs in, i dont create any manual cookie but see a connect.sid cookie is created. Now from Angular I'm sending another req:
$scope.test = function(){
$http.get('\test').then(function(response){
if(response){
console.log(response);
} else {
console.log("Nothing Returned!");
}
});
}
And in node :
app.use(session({
secret: 'mysecret',
resave: true,
saveUninitialized: true
}));
//Passport Init
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
app.get('\test', function(req, res){
//Tried the following (one at a time) :
var user = req.user;
var user = req[user];
var user = req["user"];
var user = req.session;
console.log(user);
res.send(user);
});
None of the above works. I get res code 200 but nothing in response.data in Angular and nothing in undefined in node console.
Im doing this cause I think :
After user logs in, Passportjs creates session is persisted until its destroyed by logout.
After user logs in, there is no need to create a cookie and send it to Angular. Passport does this automatically.
When Angular sends any request, node can access the session of req and verify with it's own session.
Am I correct with all these 3 points?
Many thanks!
EDIT
My mongoose schema:
var UserSchema = mongoose.Schema({
id : {type:String, default:"abc123"},
username: {type:String, index: true},
password: String,
email: {type:String, unique:true}
});
module.exports = mongoose.model('User', UserSchema);
EDIT 2
Adding output that i get when placed the express session before passport session
EDIT 3
My strategy :
passport.use(new LocalStrategy(
function(username, password, done){
User.findOne({username: username}, function(err, doc){
if(err) {
// console.log(err);
return done(err);
}
return done(null, doc);
});
}
));
You need to change the order, put 'express session' before 'passport session'. It should work this way:
app.use(session({
secret: 'mysecret',
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
http://passportjs.org/docs/configure
Are you calling passport.initialize() and passport.session() ?
passport.session is the call that reads the cookie and stores user in req object.
Check this answer for more details: What does passport.session() middleware do?

User not recognized by Express Passport with my strategy

I have a strange behavior with my Angular - Express + Passport behavior.
On my application, a user is authenticated this way: the AngularJS application calls an external service, linked to NTML, which returns several information such as the email of the current user.
Then, the AngularJS application calls a REST service on my Express backend (/rest/userProfile) to get the full profile of the user. That's when I authenticate the user on the back-end.
However, at the same time, the AngularJS application (during its initialization) calls several others REST api on my back-end (such as retrieving the application configuration in /rest/config, some other stuffs to display on the homepage). These calls are not protected and are generally handled before the call to /rest/userProfile.
In others words, the Express session is created by the first request received on the back-end, which is generally /rest/config and not /rest/userProfile (I think this point is really important).
After all that initialization, the user can call some protected REST api, like /rest/foo/.
But it appears that sometimes, the user is then not recognized on the back-end, despite the fact that the request contains the Express cookie (connect.sid). The logs show that the request object does not contain the passport property.
If I refresh one or two times the browser, everything start to work correctly, i.e. the user is finally recognized. After that, during some times, I can restart my browser and it will work directly without problem.
It seems that if I delay all the requests (like /rest/config) to ensure that /rest/userProfile is the first request received on the server, everything works correctly (i.e. the user will be recognized correctly on protected routes).
Is my understanding correct, in the sense that with my current implementation I have to make the call to /rest/userProfile be the first request received on the backend, so the session created by Passport will contains the user information?
If yes, what I have to change in my implementation (cf. below) to make it work, regardless when the call to /rest/userProfile is received (of course before any protected route)?
If no, what is wrong on my site? Any clue?
The code
On my index.js, I set the following Express middlewares:
app.use(session({
secret: 'xxx',
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
On my main route JS file:
passport.serializeUser(function(user, done) {
console.log('[serialize user]', user);
done(null, user.username);
});
passport.deserializeUser(function(username, done) {
console.log('[deserialize username]', username);
User.findOne({username: username}, function(err, user) {
done(err, user);
});
});
passport.use('ntml-strategy', new LocalStrategy({
usernameField: 'mail',
passwordField: 'password',
passReqToCallback: true
},
function(req, username, password, done) {
console.log('[ntml strategy]', username);
User.findOne({username: username}, function(err, user) {
if (err) {
return done(err);
} else if (user && user !== null) {
return done(null, user);
}
// User does not exist in DB.
// We should create a new user with data received from client.
var newUser = new User({
username: username,
roles: ['user']
});
User.create(newUser, function(err, userSaved) {
if (err) {
return done(err);
}
return done(null, userSaved);
});
});
}));
// The REST api to get user profile
app.post('/rest/userProfile', passport.authenticate('ntml-strategy'), getUserProfile);
function getUserProfile(req, res) {
var user = req.user;
console.log('[getUserProfile]', user);
if (!user) {
return res.status(401).end();
}
res.json({
username: user.username,
roles: user.roles
});
}
// In other file, another route:
app.get('/rest/foo/', isAuthenticated, getUserStuff);
function isAuthenticated(req, res, next) {
if (!req.isAuthenticated()) {
return res.status(401).end();
}
next();
}
function getUserStuff(req, res, next) {
// Do stuff
}
On the User model, I've set the passport-local-mongoose:
User.plugin(passportLocalMongoose, {
usernameField: 'username',
usernameUnique: true
});
Note that removing that plugin does not change anything in the behavior.
Thanks.
For versions: node 5.5, express 4.10.8, passport 0.3.2, passport-local 1.0.0 and Angular 1.5.

PassportJS with NodeJS not returning errors (MEAN stack)

I'm running a MEAN stack with PassportJS for authentication, and I'm having an issue with my signup module interacting with my Angular controller. Basically, the errorCallback is never called, and I'm not sure how to properly use the Passport done() implementation.
I have a basic signup form that upon submission, calls this request:
$http.post('/api/signup', {
name: $scope.user.name,
email: $scope.user.email,
password: $scope.user.password,
userSince: new Date().now
}).then(
function successCallback(res) {
$rootScope.message = 'Account Created';
console.log('Success'+res);
console.dir(res,{depth:5});
$location.url('/signupConf');
}, function errorCallback(res) {
$rootScope.message = 'Failure, see console';
console.log('Error: '+res);
console.dir(res,{depth:5});
$location.url('/');
});
With the express route:
app.post('/api/signup', passport.authenticate('local-signup'),function(req, res) {
console.log('User: ' + req.user.email);
});
And finally the Passport (adapted from a Scotch.io tut) module, abridged a little:
passport.use('local-signup', new LocalStrategy({
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done) {
console.log("Signup Request: "+email);
process.nextTick(function() {
User.findOne({ 'email' : email }, function(err, user) {
if (err) { return done(err); }
// check to see if theres already a user with that email
if (user) {
console.log("User not created, already exsists: "+user);
return done(err, false, {message: 'Username already exsists.'});
} else {
// if there is no user with that email
// create the user
var newUser = new User();
//a bunch of data creation here
newUser.save(function(err) {
if (err) {throw err;}
console.log("Sucessfully created: "+newUser);
return done(null, newUser);
});
}
});
});
}));
Everything runs fine, users are created corrected, and if a user with a given email exists, a new one isn't written over it. However, no matter what, successCallback is called. When a username already exist, I can see a 401 error in the browser console. When its a bad request (i.e. not all fields filled), a 400 error.
All the server side console.logs work fine, leading me to think there's something wrong in my angular frontend, or how the backend is responding to the request.
(Scotch.io tutorial credit: https://scotch.io/tutorials/easy-node-authentication-setup-and-local)
The problem was sort of staring me in the face, it was in my route handling.
app.post('/api/signup', function(req, res, next) {
passport.authenticate('local-signup', function(err,user,response) {
//handle responses based on state of user and err
})
(req, res, next);
});

Create account with social login (facebook) and authenticate it angular-fullstack generator

I'm facing a problema with social signup because its not logging after its created as in local signup. When redirects, api/users/me is not accessible..is unauthorized (401), different from what i get in local signup, that redirects with user information.
in facebook/index.js I have default gets
.get('/', passport.authenticate('facebook', {
scope: ['email', 'user_about_me'],
failureRedirect: '/signup',
session: false
}))
.get('/callback', passport.authenticate('facebook', {
failureRedirect: '/signup',
session: false
}), auth.setTokenCookie);
and in auth.service.js I have the default functions
function isAuthenticated() {
return compose()
// Validate jwt
.use(function(req, res, next) {
// allow access_token to be passed through query parameter as well
if (req.query && req.query.hasOwnProperty('access_token')) {
req.headers.authorization = 'Bearer ' + req.query.access_token;
}
validateJwt(req, res, next);
})
// Attach user to request
.use(function(req, res, next) {
User.findByIdAsync(req.user._id)
.then(function(user) {
//user here is undefined, it shouldn't be. i want to find out why.
if (!user) {
return res.status(401).end();
}
req.user = user;
next();
})
.catch(function(err) {
return next(err);
});
});
}
function signToken(id, role) {
return jwt.sign({ _id: id, role: role }, config.secrets.session, {
expiresInMinutes: 60 * 5
});
}
/**
* Set token cookie directly for oAuth strategies
*/
function setTokenCookie(req, res) {
if (!req.user) {
return res.status(404).send('Something went wrong, please try again.');
}
var token = signToken(req.user._id, req.user.role);
res.cookie('token', token);
res.redirect('/');
}
Could anyone help me with this...Am I missing something?
Thanks in advance.
I had the similar issue. I had modified Angular full-stack code with a customizable backend URL.
https://github.com/kannach/AFSPhonegap/blob/master/client/components/services/config.service.js
I was testing the facebook login in localhost, whereas my backend url was pointing to my production server. Once I chanded the backed url to localhost, then everything worked as expected

Resources