Node / Angular / Passport / Satellizer Token - Based Facebook Authentication not returning token - angularjs

I am using Satellizer on Angular with a Node backend doing authentication with Passport.js. I have implemented the login flow according to the Satellizer documentation and am able to return a token to the browser through my Passport / Node server. However, when I return the token, it is returned to the popout window, not the Angular application itself. As a result, I receive this error in the angular application after the popout window self-closes:
Expecting a token named "token
Here are my passport routes:
app.post('/login/facebook', passport.authenticate('facebook-login', { 'scope': ['email'] }))
app.get('/login/facebook-callback', passport.authenticate('facebook-login'), function(req, res) { tokenHelper.createSendToken(req.user, res); })
And here is my Passport Facebook strategy:
var facebookLoginStrategy = new FacebookStrategy({
clientID: process.env.FACEBOOK_APP_ID,
clientSecret: process.env.FACEBOOK_APP_SECRET,
callbackURL: "http://localhost:8080/login/facebook-callback",
passReqToCallback: true,
profileFields: ['email']
}, function(req, accessToken, refreshToken, profile, done) {
if (!req.user) {
User.findOne({
"facebookData.id": profile.id
}, function(err, user) {
if (err) return done(err);
if (user) {
// Authenticate
console.log('found user')
return done(null, user);
} else {
// Register
console.log('making new user')
var newUser = new User();
newUser.facebookData = profile
newUser.email = profile.emails[0].value
newUser.username = profile.emails[0].value
console.log(newUser)
newUser.save(function(err) {
if (err) throw err;
return done(null, newUser);
});
}
});
} else {
// Authorize
console.log('updating user')
var user = req.user
user.facebookData = profile;
user.save(function(err) {
if (err) throw err;
return done(null, user);
});
}
})
passport.use('facebook-login', facebookLoginStrategy)
I installed passport session even though I'm using tokens, but it still returns the token to the wrong place. How can I make Satellizer pass the token it receives in the popout window forward to the angular application? Or do I need to modify my authentication flow to accommodate these frameworks? Thanks for your help!

Related

Getting a 401 status when trying to reach protected route using passport-jwt

I am trying to get JWT working with passport.js, I have a local strategy that signs up and another that logs in a user. Currently, I have it return the token by doing:
req.login(user, {session: false}, (err) => {
if (err) {
res.send(err);
}
var jwtUser = {
_id: user.id,
email: user.email
};
const token = jwt.sign(jwtUser, config.passport.jwtSecret);
return res.json({jwtUser, token});
});
This returns an object like:
{"jwtUser":
{
"_id":"5c55f0be9ddcf71a704d92b2",
"email":"john.doe#example.com"
},
"token":"<token>" // redacted this because it contains my personal email
}
So I am getting a token back that is correct (I've checked using an online decoder, it gives the correct user ID and the correct email).
When I use this route to try and test whether the JWT strategy is working or not I get a 401 unauthorized access message.
Here is my JWT strategy
var opts = {};
opts.jwtFromRequest = ExtractJWT.fromAuthHeaderAsBearerToken();
opts.secretOrKey = config.passport.jwtSecret;
passport.use('jwt', new JWTstrategy(opts, function(jwt_payload, done) {
console.log('payload received: ', jwt_payload);
User.findOne({id: jwt_payload.id}, function(err, user) {
console.log('User: ', user);
if (user) {
console.log(user);
return done(null, user);
}
if (err) {
return done(err, false);
}
});
}));
My route
router.get('/auth/test', passport.authenticate('jwt', { session: false }), (req, res) => {
res.send('You reached a private route.');
});
I have my local strategy working using the same method of calling passport.
I think I have included everything of value, if something is missing please say and I will update the OP with it.
Thanks in advance!
EDIT**
I should note I am using postman to test this and using the authorization method of bearer token.

how to return an error after login failed in passport oauth

I have a node js server, as a login strategy I use passport with google OAuth.
this is my code
passport.use(new GoogleStrategy({
clientID: ...,
clientSecret: ...,
callbackURL: "http://localhost:3000/users/googleAuth/callback"
},
function(accessToken, refreshToken, profile, done) {
process.nextTick(function(){
UserDB.findOne({'google.id': profile.id}, function(err, user){
if(err)
return done(err);
if(user)
if(user.active)
return done(null, user);
else
return done("user was disabled");
else {
var newUser = new UserDB();
newUser.admin = false;
newUser.email = profile.emails[0].value;
newUser.google.id = profile.id;
newUser.google.token = accessToken;
newUser.google.name = profile.displayName;
newUser.google.email = profile.emails[0].value;
newUser.save(function(err){
if(err)
console.log(err);
else
return done(null, newUser);
});
console.log(profile);
}
});
});
}
));
and this is the callback
router.get('/googleAuth/callback',
passport.authenticate('google', {successRedirect:'/'}), function (req,res) {
if(!req.isAuthenticated())
res.redirect('/');
});
the user have an active property ,if it set to false the user can't log in (you can see this in the code) , when this happen I want to redirect the user to the main page with an error message, I tried to use res.redirect('/'), however it didn't work ,the user is just stack in the screen where you pick a google user ,I also tried to add failureRedirect property but with the same results.
How can I redirect the user? is it also possible to send a message?

how to send user profile data on success redirect with passport?

I'm quite new to Node.js, and i'm learning authentication with passport, in my node application i have following lines which authenticates user with google and fires a callback after successful authentication,
// send to google to do the authentication
app.get('/auth/google', passport.authenticate('google', { scope : ['profile', 'email'] }));
// the callback after google has authenticated the user
app.get('/auth/oauth/callback',passport.authenticate('google', {successRedirect : 'http://127.0.0.1:1234/testbot',failureRedirect : '/'}));
i want to send the user profile data to the page registered with successRedirect, how can i do that?
my passport strategy for authentication with google is like so
passport.use(new GoogleStrategy({
clientID : configAuth.googleAuth.clientID,
clientSecret : configAuth.googleAuth.clientSecret,
callbackURL : configAuth.googleAuth.callbackURL,
passReqToCallback : true // allows us to pass in the req from our route (lets us check if a user is logged in or not)
},
function(req, token, refreshToken, profile, done) {
console.log("Its here ");
// asynchronous
process.nextTick(function() {
// check if the user is already logged in
if (!req.user) {
User.findOne({ 'UserName' : req.body.email }, function(err, user) {
if (err)
return done(err);
if (user) {
// if there is a user id already but no token (user was linked at one point and then removed)
if (!user.google.token) {
user.google.token = token;
user.google.name = profile.displayName;
user.google.email = (profile.emails[0].value || '').toLowerCase(); // pull the first email
user.save(function(err) {
if (err)
return done(err);
return done(null, user);
});
}
return done(null, user);
} else {
var newUser = new User();
newUser.UserName= (profile.emails[0].value || '').toLowerCase();
newUser.google.id = profile.id;
newUser.google.token = token;
newUser.google.name = profile.displayName;
newUser.google.email = (profile.emails[0].value || '').toLowerCase(); // pull the first email
newUser.save(function(err) {
if (err)
return done(err);
return done(null, newUser);
});
}
});
} else {
// user already exists and is logged in, we have to link accounts
var user = req.user; // pull the user out of the session
user.google.id = profile.id;
user.google.token = token;
user.google.name = profile.displayName;
user.google.email = (profile.emails[0].value || '').toLowerCase(); // pull the first email
user.save(function(err) {
if (err)
return done(err);
return done(null, user);
});
}
});
}));
Im not sure what front end your using but if its React with Redux and if you have SSR you can preloadState with the req.user info by firing an action from your server. Here's documentation on that.
Or if you have session's setup you can make a get request when your front end loads and respond back with the req.user info.

Nodejs express integration authentification local and facebook

I actually develop a restfull server using NodeJS and express.
I've already implemented oauth2 protocol in order to secure my API.
I want to add Facebook authentication but I don't manage to integrate the facebook authentification with my local authentication.
server.js
router.route('/oauth/local')
.post(oauth2Controller.token);
router.route('/oauth/facebook')
.get(passport.authenticate('facebook-token'), oauth2Controller.token);
//impossible to call oauth2Controller.token
oauth2.js
var oauth2orize = require('oauth2orize')
var User = require('../models/user');
var AccessToken = require('../models/accesstoken');
var RefreshToken = require('../models/refreshtoken');
var passport = require('passport');
var server = oauth2orize.createServer();
server.exchange(oauth2orize.exchange.password(function(application, username, password, scope, callback){
User.findOne({username: username}, function(err, user){
if (err)
return (callback(err));
if (!user)
return (callback(null, false));
user.verifyPassword(password, function(err, isMatch){
if (err)
return (callback(err));
if (!isMatch)
return (callback(null, false));
var accessToken = new AccessToken({
user: user.username,
application: application.oauth_id,
scope: '*'
});
accessToken.save(function(err){
if (err)
return (callback(err));
});
var refreshToken = new RefreshToken({
user: user.username,
application: application.oauth_id
});
refreshToken.save(function(err){
if (err)
return (callback(err));
});
callback(null, accessToken.value, refreshToken.value);
});
})
}));
server.exchange(oauth2orize.exchange.refreshToken(function(application, refreshToken, scope, callback){
RefreshToken.findOne({value: refreshToken}, function(err, token){
if (err)
return (callback(err));
if (!token)
return (callback(null, false));
var accessToken = new AccessToken({
user: token.user,
application: application.oauth_id,
scope: '*'
});
accessToken.save(function(err){
if (err)
return (callback(err));
});
callback(null, accessToken.value, refreshToken.value);
});
}));
exports.token = [
passport.authenticate(['clientBasic'], {session: false}),
server.token(),
server.errorHandler()
];
auth.js
passport.use(new FacebookTokenStrategy({
clientID: ID_CLIENT_FACEBOOK,
clientSecret: SECRET_CLIENT_FACEBOOK
},
function(accessToken, refreshToken, profile, done) {
//Do something here
done(null, profile);
}));
The local authentication and facebook authentication work fine.
But after be authenticated with facebook, I don't manage to give the needed informations to oauth.token in order to obtain tokens for my API.
after authenticate with face book store token value inside the db.
ask the oAuth server for refresh token
in refresh token you can store scope information

sails.js + passport.js : managing sessions

I am trying to implement a facebook connection in sails using passport. Therefore, I've created a passport.js file in my services folder, the code is given below. It looks like the login is done successfully, however the user serialization doesn't seem to work as the console.log that I put in it never appears in the console and I cannot access the user id trhough req.user once the user is supposed to be logged in. Did anyone managed to get passport working with sails?
var passport = require('passport')
, FacebookStrategy = require('passport-facebook').Strategy,
bcrypt = require('bcrypt');
// helper functions
function findById(id, fn) {
User.findOne(id).done( function(err, user){
if (err){
return fn(null, null);
}else{
return fn(null, user);
}
});
}
function findByUsername(u, fn) {
User.findOne({
username: u
}).done(function(err, user) {
// Error handling
if (err) {
return fn(null, null);
// The User was found successfully!
}else{
return fn(null, user);
}
});
}
// Passport session setup.
// To support persistent login sessions, Passport needs to be able to
// serialize users into and deserialize users out of the session. Typically,
// this will be as simple as storing the user ID when serializing, and finding
// the user by ID when deserializing.
passport.serializeUser(function(user, done) {
console.log("utilisateur serilizé!");
done(null, user.uid);
});
passport.deserializeUser(function(id, done) {
//console.log("coucou");
findById(id, function (err, user) {
done(err, user);
});
});
// Use the LocalStrategy within Passport.
// Strategies in passport require a `verify` function, which accept
// credentials (in this case, a username and password), and invoke a callback
// with a user object.
// using https://gist.github.com/theangryangel/5060446
// as an example
passport.use(new FacebookStrategy({
clientID: 'XXX',
clientSecret: 'XXX',
callbackURL: "http://localhost:1337/callback"
},
function(accessToken, refreshToken, profile, done) {
User.findOne({uid: profile.id}, function(err, user) {
if (err) { return done(err); }
if (user) {
//console.log('momo');
User.update({uid : user.uid},{token : accessToken},function(){done(null, user);});
} else {
console.log(profile);
var user_data = {
token : accessToken
, provider: profile.provider
, alias: profile.username
, uid: profile.id
, created: new Date().getTime()
, name: {
first: profile.name.givenName
, last: profile.name.familyName
}
, alerts: {
email: true
, mobile: false
, features: true
}
};
console.log(user_data);
User.create(user_data).done(function(err, user) {
console.log(err);
if(err) { console.log("err");throw err; }
done(null, user);
});
}
});
}
));
While I do not have a direct answer for you, this was extremely useful to when getting it to work with GitHub OAuth: https://github.com/stefanbuck/sails-social-auth-example/blob/master/config/middleware.js
This is an entire, recent, Sails.js application implementing passport so it might be of use to you to side-by-side the two in the debugger and find out what is going on.
Check out this easy and full implementation for sails.js with passport.js supporting both Email, Twitter and Facebook.
https://github.com/bmustata/sails-auth-super-template

Resources