I'm using the passport module to authenticate a user and generate a jwt token.
Now I want to make facebook login possible. I'm in the phase that I get a fb token and facebook id.
What am I supposed to do with this info? Currently I make a new user that has a variable with facebook id but without a password.
Without a password I can't generate a jwt token, thus I cannot login.
How does this work?
My front end is angular and my API is written with nodejs, express & mongoose.
Passport 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, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
generatejwt code:
UserSchema.methods.generateJWT = function() {
// set expiration to 60 days
var today = new Date();
var exp = new Date(today);
exp.setDate(today.getDate() + 60);
return jwt.sign({
_id: this._id,
username: this.username,
exp: parseInt(exp.getTime() / 1000),
}, 'SECRET');
};
You need to create 2 routes :
1) This will be called to login to facebook.
2)Callback route if the user authentication is successful.(This callback route needs to be registered in the facebook developer portal.
//Facebook Login
app.route('/auth/facebook')
.get(passport.authenticate('facebook', { scope: 'email' }));
// Callback
app.route('/auth/facebook/callback')
.get(passport.authenticate('facebook'),users.generateJWT);
Define a facebook strategy that will store the user details (id, token, email) in your database
var facebookStrategy = new FacebookStrategy({
clientID: cfg.facebook.clientID,
clientSecret: cfg.facebook.clientSecret,
callbackURL: cfg.facebook.callbackURL,
profileFields: ['id', 'email', 'first_name', 'last_name']
},
function(token, refreshToken, profile, done) {
console.log("Token: "+ token);
console.log("RefreshToken: "+ refreshToken);
console.log("profile: "+ profile);
process.nextTick(function() {
User.findOne({ 'facebook.id': profile.id }, function(err, user) {
if (err)
return done(err);
if (user) {
console.log("User Found");
return done(null, user);
} else {
console.log("Creating user");
var newUser = new User();
console.log("Token: "+ token);
newUser.facebook.id = profile.id;
newUser.facebook.token = token;
newUser.facebook.name = profile.name.givenName + ' ' + profile.name.familyName;
newUser.facebook.email = (profile.emails[0].value || '').toLowerCase();
newUser.save(function(err) {
if (err)
throw err;
return done(null, newUser);
});
}
});
});
});
In the controller, write the below code for callback route:
/**
* Generate JWT Token
*/
exports.generateJWT = function(req, res) {
var token;
token = req.user.generateJwt();
res.status(200);
res.json({
"token" : token
});
};
Related
I generated token with JWT using node and angular, and can't check if user is authorized.
Node:
module.exports.authenticate = function(req, res) {
var user = new User(req.body);
User.findOne({
username: req.body.username
}, function(err, user) {
if (err) throw err;
if (!user) {
res.json({ success: false, message: 'Authentication failed. User not found.' });
}
else if (user) {
if (user.password != req.body.password) {
res.json({ success: false, message: 'Authentication failed. Wrong password.' });
}
else {
var token = jwt.sign(user, config.secret, {
expiresIn: 60*60*24
});
res.json({
success: true,
token: token
});
}
}
});
};
Angular:
$http(req)
.then(function (response) {
console.log(response.data.success);
if(response.data.success) {
var user = localStorage.setItem('token', JSON.stringify(response.data));
token = localStorage.getItem('token');
// console.log('User info: ', JSON.parse(getuser));
// window.location = "/dashboard";
return response.data;
}
}, function (response) {
}
);
}
How can I check token when I change route?
And generically how can I use Token?
Angular ui-router provides $routeChangeStart event while you change a route. You can use it in the following way.
$rootScope.$on('$routeChangeStart', function (event, next, current){
//you can code here something to be run on changing routes
}
You might want to have a look here for detailed event documentation.
Regarding a more generic implementation , you can create a service to keep your token at the time of login or whenever you get it. Thereafter you can keep getting the token from the service for any future comparisons.
you should install "cookie-parser"
npm i cookie-parser
and go to index.js file and add
const cookieParser = require('cookie-parser');
app.use(cookieParser());
it works for me
I create a jwt token and stored in database. when login successfully done i want to redirect to home page with token. how could i do that.
My Nodejs file.
app.post('/authenticate', function(req, res, next) {
User.findOne({name: req.body.name}, function(err, user) {
if (err) {throw err;}
if (!user) {
res.json({ success: false, message: 'Authentication failed. User not found.' });
} else if (user) {
// check if password matches
if (user.password !== req.body.password) {
res.json({ success: false, message: 'Authentication failed. Wrong password.' });
} else {
// if user is found and password is right
// create a token
var token = jwt.sign(user, app.get('superSecret'), {
expiresIn: 1440 // expires in 24 hours
});
// return the information including token as JSON
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
}
});
});
My angularjs file
var app = angular.module('loginApp', []);
// Controller function and passing $http service and $scope var.
app.controller('loginCtrl', function($scope, $http) {
// create a blank object to handle form data.
$scope.user = {};
// calling our submit function.
$scope.submitForm = function() {
// Posting data to file
$http.post('/tokken/login/', $scope.user).then(function (response) {
//$http.defaults.headers.common['Token'] = token
if (response.errors) {
// Showing errors.
$scope.errorName = response.errors.name;
$scope.erroPassword = response.errors.password;
} else {
$scope.message = response.data;
}
});
};
});
I print token value in same login page. I want to redirect to another page with the token
I am working on a simple blog website based on angular.js + node.js and mongodb using express template.
I hit with $http from angular controller by POST method to a api named users.js where login is authenticated using passport.authenticate method.
I require passport-local login strategies in users.js.
But it's not working.here is angular login service code and node users api code.
Can anybody tell me how can use passport.js in angular and node?
angular routing through a service
app.service('Auth',function($location,$http,$localStorage){
var userLogin ;
return{
setLogIN:function(email,password){
$http({
method: 'POST',
url: '/users/login', //users.js having node routing.
data: {email:email, password:password},
})
node routing in user
router.post('/login',passport.authenticate('local', {
// use passport-local for authentication
successRedirect : '/profile',
failureRedirect : '/login',
failureFlash : true
}));
passport-local strategy
app.use(passport.initialize());
app.use(passport.session());
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, {alert: 'Incorrect username.'});
}
if (user.password != password) {
return done(null, false, {alert: 'Incorrect password.'});
}
return done(null, user);
});
}
));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
function isAuthenticated(req,res,next){
if(req.isAuthenticated())return next();
res.redirect('/');
}
So I want to authenticate using passport, but use the client side templating/routing to keep the proper authentication.
Can someone please point me in the right direction? Or tell me if what I am doing is completely misguided?
edit : the error I AM getting with my code is it's not redirecting to profile page
TypeError: POST http://localhost:3000/users/login 500 Internal
Server Error
Not a valid User
i found solution to my question..
how to use passport with angular-nodejs routing.......
//angular js routing
$scope.userlogin=function(){
$http({
method:"post",
url:'/users/login',
data:{username:$scope.username,password:$scope.password},
}).success(function(response){
$scope.userData = response;
$localStorage.userData = $scope.userData;
console.log("success!!");
$location.path("/profile")
}).error(function(response){
console.log("error!!");
$location.path("/login")
});
}
i use POST method and hit to node (users.js) controller and get response from it. if user authentication is successful then it relocate to profile view otherwise remain on login view.
//add these two lines to app.js
// var app = express();
app.use(passport.initialize());
app.use(passport.session());
//node routing
// add passport-stretegies to users.js
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.password != password) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
// console.log(user)
});
}));
//passport serialize user for their session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
//passport deserialize user
passport.deserializeUser(function(id, done) {
user.findById(id, function(err, user) {
done(err, user);
});
});
//router on same page
router.post('/login',passport.authenticate('local'),function(req,res){
res.send(req.user);
//console.log(req.user);
});
get a hit from angular side throught post method it use passport-local method for authentication if user is authenticated seccessfully then authenticated user is sent as response..
By default, LocalStrategy expects dictionary parameters to be named username and password.
If you want to use email instead of username, then you should define them in your strategy:
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
function(username, password, done) {
// ...
}
));
For your case, it should be:
passport.use(new LocalStrategy({
usernameField: 'email',
passwordField: 'password'
},
function (username, password, done) {
User.findOne({username: username}, function (err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, {alert: 'Incorrect username.'});
}
if (user.password != password) {
return done(null, false, {alert: 'Incorrect password.'});
}
return done(null, user);
});
}
));
I'm very new to angular, so my knowledge is based on tutorials and even then I don't succeed.
I need to authenticate using a google account. That works, I get a token where my api calls could be authorized with. But after login the pop up window should dismiss and I should be redirected to the homepage. This doesn't work.
this is my controller
angular.module('MyApp').controller('loginController', ['$scope', '$auth', '$location','loginService', loginController]);
function loginController($scope, $auth, $location, loginService) {
$scope.authenticate = function(provider) {
$auth.authenticate(provider).then(function(data) {
loginService.saveToken(data.data.token);
console.log('You have successfully signed in with ' + provider + '!');
$location.path('http://localhost/#/home');
});
};
};
in app.js I have my configuration. this is not my work but a friend who is an intern as wel as me, he is responsible for a mobile application, where he uses the same function to get his token, and it works.
authProvider.google({
clientId: CLIENT_ID,
redirectUri: 'http://localhost:3000/api/users/signIn'
});
$authProvider.storage = 'localStorage'; // or 'sessionStorage'
$authProvider.loginRedirect = 'http://localhost/#/home';
This is the controller in node where the url is redirected to (google developer console)
router.get('/signIn', function(req, res) {
//console.log(req);
var code = req.query.code;
oauth2Client.getToken(code, function(err, tokens) {
if (!err) {
https.get("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" + tokens.access_token, function(response) {
// Continuously update stream with data
var body = '';
response.setEncoding('utf8');
response.on('data', function(d) {
body += d;
});
// Data fetched
response.on('end', function() {
var parsed = JSON.parse(body);
// Check if client_id is from the right app
if (parsed.issued_to == '343234242055-vd082vo0o8r8lmfvp1a973736fd98dht.apps.googleusercontent.com') {
User.getGoogleId(parsed.user_id, function(err, user) {
if (err) {
res.status(500).send({
message: 'not authorized app'
});
}
// No user returned, create one
if (!user) {
// Request user info
oauth2Client.setCredentials(tokens);
plus.people.get({
userId: 'me',
auth: oauth2Client
}, function(err, plusUser) {
if (err) res.status(500).send({
message: 'not authorized app'
});
else {
// Create new user
User.create(plusUser.name.givenName, plusUser.name.familyName, (plusUser.name.givenName + "." + plusUser.name.familyName + "#cozmos.be").toLowerCase(), parsed.user_id, function(err, newUser) {
if (err) res.status(500).send({
message: 'not authorized app'
});
else {
res.statusCode = 200;
return res.send({
response: 'Success',
id: user._id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
token: tokens.access_token
});
}
});
}
});
} else {
// Return user
res.statusCode = 200;
return res.send({
response: 'Success',
id: user._id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
token: tokens.access_token
});
}
});
}
// if not right app, return unauthorized response
else {
res.status(500).send({
message: 'not authorized app'
});
}
});
});
}
});
});
So I login, I get asked to give permission to the application to use my account info, I get a json response where I can see my name, email and token, and that's it
Even within the company where I work, no one could find an answer. So I came with a solution myself. I don't use satellizer anymore.
.when('/access_token=:access_token', {
template: '',
controller: function($window, $http, $location, $rootScope) {
var hash = $location.path().substr(1);
var splitted = hash.split('&');
var params = {};
for (var i = 0; i < splitted.length; i++) {
var param = splitted[i].split('=');
var key = param[0];
var value = param[1];
params[key] = value;
$rootScope.accesstoken = params;
}
console.log(params.access_token);
var json = {
Token: params.access_token
};
$window.localStorage['token'] = params.access_token;
$http.post('http://localhost:3000/api/users/signIn', json).success(function(data, status) {
console.log(data);
}).error(function(err) {
console.log(err);
});
$location.path("/home");
}
/*controller: 'createNewsFeed',
templateUrl: 'homepage.html'*/
}).
So redirect the page by itself. Because the authentication works on the backend side, I can get a access token, which is the only thing I really need for future use of my rest api. I defined a route where, after receiving the json with the token, my browser is manually redirected to with $window.location. So when that page is loaded (not visible for the user, it goes too fast to notice) I analyse the token, save the token, analyse authentication, when that is successful I manually redirect to the homepage.
In my mongodb, there is clearly a User with username "testuser", but I am still getting "failed to login!" when I enter this in. Note: Not using the password yet. Just trying to make sure I can check that the entered username exists first.
navbar-login.jade
.navbar-right(ng-controller="mvNavBarLoginCtrl")
form.navbar-form
.form-group
input.form-control(placeholder="email", ng-model="username")
.form-group
input.form-control(type="password", placeholder="password", ng-model="password")
button.btn.btn-primary(ng-click="signin(username, password)") Sign In
mvNavBarLoginCtrl.js (I keep getting "failed to login!", which means {success:false}, which I believe means the user wasn't found)
angular.module('app').controller('mvNavBarLoginCtrl', function($scope, $http) {
$scope.signin = function(username, password) {
$http.post('/login', {username:username, password:password}).then(function(response) {
if(response.data.success) {
console.log("logged in!");
}
else {
console.log("failed to login!");
}
})
}
});
routes.js (I get the "no user found.")
app.post('/login', function(req, res, next) {
var auth = passport.authenticate('local', function(err, user) {
if(err) {return next(err);}
if(!user) {
console.log("no user found.");
res.send( {success:false} );
}
// we are using XHR and not a form to login so we gotta do this
req.logIn(user, function(err) {
if(err) {return next(err);}
res.send( {success:true, user:user} );
})
})
auth(req, res, next);
})
server.js
var User = mongoose.model('User');
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne( {'username': username} ).exec(function(err, user) {
console.log(user);
if(user) {
return done(null, user);
}
else {
return done(null, false);
}
});
}
));
passport.serializeUser(function(user, done) {
if(user) {
done(null, user._id);
}
});
passport.deserializeUser(function(id, done) {
User.findOne( {_id: id} ).exec(function(err, user) {
if(user) {
return done(null, user);
}
else {
return done(null, false);
}
})
});
express.js config (not sure if I did this right with Express 4)
app.set('views', config.rootPath+ '/server/views');
app.set('view engine', 'jade');
app.use(morgan('dev'));
app.use(cookieParser());
app.use(bodyParser.urlencoded({extended:true}));
app.use(session({secret: '<mysecret>', saveUninitialized: true, resave: true}));
app.use(passport.initialize());
app.use(passport.session());
app.use(stylus.middleware(
{
src: __dirname + '/public',
compile: compile
}
));
app.use(express.static(config.rootPath + '/public'));
passport.use(new LocalStrategy...) was not being called.
This has to do with the new Express 4 config. I needed to add bodyParser.json() to express.js:
app.use(bodyParser.json()); // parse application/json
app.use(bodyParser.urlencoded({ extended: true })); // parse application/x-www-form-urlencoded
I was unable to find any documentation for this. All of the passport.js documentation seems to be outdated and intended for Express 3 which only requires an app.use(express.bodyParser());. The middleware config is the culprit if anyone else runs into this issue.
Can you check in your passport.js file if the username is undefined or not? Just console.log that.
And if it shows that it is not undefined, check your mongodb database to see if anything is actually saved in there. Grab robomongo to check this. http://robomongo.org/
var User = mongoose.model('User');
passport.use(new LocalStrategy(
function(username, password, done) {
/*Check if these values exist, if they do something is wrong in mongodb*/
console.log('THIS IS THE USERNAME', username);
console.log('THIS IS THE PASSWORD', password);
User.findOne( {'username': username} ).exec(function(err, user) {
console.log(user);
if(user) {
return done(null, user);
}
else {
return done(null, false);
}
});
}
));
passport.serializeUser(function(user, done) {
if(user) {
done(null, user._id);
}
});
passport.deserializeUser(function(id, done) {
User.findOne( {_id: id} ).exec(function(err, user) {
if(user) {
return done(null, user);
}
else {
return done(null, false);
}
})
});