I'm trying to implement facebook login with vue-authenticate and passport.
I succeeded in logging into my Facebook account. And i got the 'Callback code' successfully.
This is my callback url
http://localhost:8080/auth/callback?code=AQD0FgQ7I2oci0m3bqOHOBE1EV3Ri1TBnVcqs2PRT8pFNa38NIMX-eYiSr2EiWKQBMoNq1yOeo1QkDG1OiDjF_xUduK-HWMlMazsaBzoGNxiAK3FQH5KQopZ9NUnM2g-UYLpihtpsaFrRVssJkm8Xue1nyKbbWX76EPnPCIEVOfGM_JE4mbENLpp6_w8gwkTS9n8dtsNptDM72UO9zE7mj34J8Yls0A1VqmoZail0J2zwu4hJCzAzbP2FZ531Vo2tCERn2F_4DKsJ-zq_ppZWxRlKuRW9WFBL0UvsuNN_ODiRFs70P3SoK85-xHwzHJvx8VrVxmLlp5x7rVOzy2E2Jma#=
So I used axios to pass the 'Callback code' to the server. because my server code(passport-facebook) is this:
router.route('/auth/facebook/callback').get(passport.authenticate('facebook', {
successRedirect : '/',
failureRedirect : '/'
}));
and axois code in Vue is
this.$http.get('/api/users/auth/facebook/callback',{
params:{
code : this.param
}
})
.then((response) => {
this.movies = param;
})
but it never works.. I don't know why. just wondering, i chaneged axios code to get('api/users/'). and wrote server code like this
router.get('/',()=>{
console.log("good");
});
it works. I can see the 'good' message in console.
Let me know how you implement social sign-in!
if you want to configure Facebook login with passport So you can simply follow these Steps As mention below:
Step 1. Add passport configuration
const passport = require('passport');
app.use(passport.initialize());
app.use(passport.session());
app.get('/success', (req, res) => res.send("You have successfully logged in"));
app.get('/error', (req, res) => res.send("error logging in"));
passport.serializeUser(function(user, cb) {
cb(null, user);
});
passport.deserializeUser(function(obj, cb) {
cb(null, obj);
});
Step 2. Setup facebook configuration
const FacebookStrategy = require('passport-facebook').Strategy;
const FACEBOOK_APP_ID = 'your app id';
const FACEBOOK_APP_SECRET = 'your app secret';
passport.use(new FacebookStrategy({
clientID: FACEBOOK_APP_ID,
clientSecret: FACEBOOK_APP_SECRET,
callbackURL: "/auth/facebook/callback"
},
function(accessToken, refreshToken, profile, cb) {
return cb(null, profile);
}
));
app.get('/auth/facebook',
passport.authenticate('facebook'));
app.get('/auth/facebook/callback',
passport.authenticate('facebook', { failureRedirect: '/error' }),
function(req, res) {
res.redirect('/success');
});
This will fix your issue
Please refer this link https://www.sitepoint.com/passport-authentication-for-nodejs-applications/
Related
I am new to node js and I am trying to make an example for authorization with google passport below is my code:
index.js
const express = require('express');
const app = express();
var passport = require('passport');
var GoogleStrategy = require('passport-google-oauth20').Strategy;
passport.use(new GoogleStrategy({
clientID : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
clientSecret : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
callbackURL : "http://localhost/google/login",
passReqToCallback : true
},
function(accessToken, refreshToken, profile, done) {
return done(); //this is the issue, I am confused with it's use
}
));
app.get('/failed', function (req, res) {
res.send('failed login')
});
app.get('/final', function (req, res) {
res.send('finally google auth has done')
});
app.get('/auth/google',
passport.authenticate('google', { scope: ['profile'] }));
app.get('/google/login',
passport.authenticate('google', { failureRedirect: '/failed' }),
function(req, res) {
// Successful authentication, redirect home.
res.redirect('/final');
});
app.listen('80', () => {
console.log('server is running')
})
Finally, My goal is to successful login with google without checking the value from DB as I am just learning it.
node index.js
and then i am opening url: http://localhost/auth/google
my program should run get /final after login with google credential but getting an error that TypeError: done is not a function
I am not getting the use of done() and how can I resolve it.
When you use passReqToCallback : true, you need to change the arguments of the callback function. req needs to be passed too as the first argument of the callback function.
your callback functions argument should be (req, accessToken, refreshToken, profile, done)
And that is why you are getting the error :
done is not a function
Try this :
passport.use(new GoogleStrategy({
clientID : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
clientSecret : "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
callbackURL : "http://localhost/google/login",
passReqToCallback : true
},
function(req, accessToken, refreshToken, profile, done) {
return done(); // it will work now
}
));
Im using passport to authenticate a user through Facebook.
The successRedirect works great [I'm redirecting into http://localhost:3000/success#_=_], but the failureRedirect doesn't, i'm getting this:
FacebookAuthorizationError: Login Error: There is an error in logging you into this application. Please try again later.
[I'm getting this in my browser-> http://localhost:3000/auth/facebook/callback?error_code=1349003&error_message=Login+Error%3A+There+is+an+error+in+logging+you+into+this+application.+Please+try+again+later.#_=_
Those are my settings:
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function (user, done) {
console.log(user);
done(null, 'this is the user');
})
passport.deserializeUser(function (id, done) {
console.log(id);
done(err, {message: 'this is the user'});
});
router.get('/auth/facebook', passport.authenticate('facebook'));
router.get(
'/auth/facebook/callback',
passport.authenticate('facebook',
{
successRedirect: '/success',
failureRedirect: '/login',
}
),
);
const FacebookStrategy = require('passport-facebook').Strategy;
const facebookStrategy = new FacebookStrategy({
clientID: staretegy.clientId,
clientSecret: staretegy.clientSecret,
callbackURL: staretegy.callbackURL,
profileFields: [
'id',
'first_name',
'middle_name',
'last_name',
],
}, (accessToken, refreshToken, profile, done) => {
done(null, {user: profile});
});
passport.use(facebookStrategy);
As i read in the docs i expected to be redirect to the /login.
/login can be accessed by the browser. (i've also tried to put this full URL path: failureRedirect: http://localhost:3000/login but it won't work, similar URL works with the successRedirect.
This seems an open issue and the main repository barely supported. But you can try to use this fork.
I had a similar issue here and have found a way to handle the error using a middleware error handler (see fbErrorHandler below):
const express = require('express'),
router = express.Router(),
passport = require('passport');
router.get(
'/facebook',
passport.authenticate('facebook')
);
function fbErrorHandler(err, req, res, next) {
// I use flash, but use whatever you want to communicate with end-users:
req.flash('error', 'Error while trying to login via Facebook: ' + err);
res.redirect('/login');
}
router.get('/facebook/callback',
passport.authenticate(
'facebook',
{
failureRedirect: '/login',
failureFlash: true
},
),
fbErrorHandler,
(req, res) => {
// Successful authentication
res.redirect('/authenticated');
}
);
module.exports = router;
I'm trying to develop a simple API in node and hiding it behind a google authentification layer, for that I'm using passport-google-oauth2 to enforce a google authentification to do some requests.
....
var GoogleStrategy = require('passport-google-oauth2').Strategy;
var passport = require('passport');
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(user, done) {
done(null, user);
});
passport.use(new GoogleStrategy({
clientID: CLIENT_ID,
clientSecret: CLIENT_SECRET,
callbackURL: "/oauth2callback",
passReqToCallback : true
},
function(request, accessToken, refreshToken, profile, done) {
console.log("passportUse access Profile ", accessToken);
done(null, accessToken);
}
));
app.get('/oauth2callback',
passport.authenticate( 'google', {
successRedirect: '/notesSuccess',
failureRedirect: '/notesNotSuccess'
}));
app.get('/notes',
passport.authenticate('google', { scope:
[ 'https://www.googleapis.com/auth/plus.login', 'https://www.googleapis.com/auth/drive'] }
), function(req, res) {
//res.json({notes: "This is your notebook. Edit this to start saving your notes!"})
})
app.get('/notesSuccess', function(req, res) {
res.json({notes: "This is your notebook. Edit this to start saving your notes!"})
})
app.get('/notesNotSuccess', function(req, res) {
res.json({notes: "AUTHENTICATION FAIL"})
})
app.get('/notes/API1', function(req, res) {
res.json({notes: "API1111111"})
})
....
The code is working more or less, at passport.use I do get all the google plus profile information and a token, so I assume that part is working.
The issue is that when I use the browser to visit localhost:8080/notes, I get the results as expected (/notesSuccess) when I login, if I'm in a private window I can see the google login page, working well so far.
My problem is if I do a query with postman using the token I was given or a new token with the same scopes I get only the login page (as if I had no Authentification header). If I query notes/API1 (no Oauth there) it works properly
Any ideas why the headers are not authentifing the query?
I have an express application where I'm using passportjs for managing authentication.
At the moment I only want to support sign in with google in my application. I have implemented this properly and is working fine. Now, I want to restrict access to to the application to only those users who are registered with the application.
Registration is done by admin so there can only be few users who are registered. At the moment, anyone with a google account is able to login to the application. Instead of this, I would like the authentication to happen with google using OAuth2.0 and I would like to check if the user exists in my database before letting the user login to the system.
Update
Following is my code as requested
var passport = require('passport');
var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
var config = require('./config');
var directoryService = require('./services/directory');
/**
* Authentication configuration
*/
module.exports = function (app, router) {
passport.serializeUser(function (user, done) {
//I want to know if this is the correct process
directoryService.findResidentByEmailAddress(user.emails[0].value).then(function (data) {
if (data == null || data.length == 0) {
done({ 'status': 'Invalid Login' });
} else {
done(null, data);
}
});
});
passport.deserializeUser(function (obj, done) {
done(null, obj);
});
passport.use(new GoogleStrategy({
clientID: config.auth.clientID,
clientSecret: config.auth.clientSecret,
callbackURL: config.auth.callbackURL,
passReqToCallback: true
},
function (request, accessToken, refreshToken, profile, done) {
process.nextTick(function () {
return done(null, profile);
});
}
));
app.use(passport.initialize());
app.use(passport.session());
router.use(function (req, res, next) {
if (req.isAuthenticated() || req.url.startsWith('/auth/')) {
return next();
}
res.redirect('/auth/login.html');
});
router.get('/auth/google',
passport.authenticate('google', { scope: ['email'] }));
router.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/login' }),
function (req, res) {
res.redirect('/');
});
router.get('/logout', function (req, res) {
req.logout();
res.redirect('/auth/login.html');
});
}
When using facebook-passport the usual thing to do is to specify the redirect_uri in the constructor of the FacebookStrategy thst you use, something like this:
passport.use("facebook", new FacebookStrategy({
//TODO: Correctly configure me
clientID: "XXXXXXX"
, clientSecret: "XXXXXXXXX"
, callbackURL: "http://localhost:3007/auth/facebook/callback"
},
function(accessToken,refreshToken,profile,done) {
User.findByFacebookId(profile.id, function(err,user) {
if(err){ return done(err);}
if(!user){ return done(null,false)}
return done(null, user);
});
})
);
Then you would set up routes like this:
app.get('/auth/facebook/login', passport.authenticate('facebook') );
app.get('/auth/facebook/login_callback', passport.authenticate('facebook', {
successRedirect:"/login_ok.html"
, failureRedirect:"/login_failed.html"
}
))
Is it possible to change the callback url so that it contains information from parameters passed to the initial login call?
NOTE: This question is more for preserving info that took me a while to work out, to avoid others going down the same paths.
I found the answer using some info found here https://github.com/jaredhanson/passport-facebook/issues/2 and through digging through the way the passport oauth2 component determines callback uris, and information about passport custom callbacks at the bottom of this page http://passportjs.org/guide/authenticate/.
Here's an example that maps calls to /auth/facebook/login/1234 to use the callback /auth/facebook/login_callback/1234
app.get('/auth/facebook/login/:id', function(req,res,next) {
passport.authenticate(
'facebook',
{callbackURL: '/auth/facebook/login_callback/'+req.params.id }
)(req,res,next);
});
app.get('/auth/facebook/login_callback/:id', function(req,res,next) {
passport.authenticate(
'facebook',
{
callbackURL:"/auth/facebook/login_callback/"+req.params.id
, successRedirect:"/login_ok.html"
, failureRedirect:"/login_failed.html"
}
) (req,res,next);
});
#OMGPOP, here you can pass in query params into your callbackUrl.
var Passport = require('passport');
var FacebookStrategy = require('passport-facebook').Strategy;
const Router = require("express").Router();
var fbConfig = {
display: "popup",
clientID: "YourFbClientId",
clientSecret: "YourFbClientSecret",
callbackURL: "http://localhost:8686/auth/facebook/callback",
profileFields: ['id', 'name', 'gender', 'displayName', 'photos', 'profileUrl', 'email']
}
Passport.use(new FacebookStrategy(fbConfig,
function(accessToken, refreshToken, profile, callback) {
return callback(null, accessToken);
}
));
Router.get("/auth/facebook", function(req, res, next) {
var callbackURL = fbConfig.callbackURL + "?queryParams=" + req.query.queryParams;
Passport.authenticate("facebook", { scope : ["email"], callbackURL: callbackURL })(req, res, next);
});
Router.get("/auth/facebook/callback", function(req, res, next) {
Passport.authenticate("facebook", {
callbackURL: fbConfig.callbackURL + "?queryParams=" + req.query.queryParams,
failureRedirect: "/login",
session: false
})(req, res, next) },
function(req, res) {
console.log(req.query.queryParams);
//do whatever you want
});
Check out my blog for more information: http://blog.pingzhang.io/javascript/2016/09/22/passport-facebook/
I was struggling to do this specifically with Angularjs, and wanted to redirect back to the same url that the login was initiated from.
My solution was to create a route in Angularjs that just implements a location back. I know this does not specifically answer the question, but I thought it would be helpful for anyone looking to do the same.
On the server:
app.get('/auth/facebook/', passport.authenticate ('facebook'));
app.get('/auth/facebook/callback', function (req, res, next) {
var authenticator = passport.authenticate ('facebook', {
successRedirect: '/fbcallback',
failureRedirect: '/'
});
delete req.session.returnTo;
authenticator (req, res, next);
})
Angular router:
when('/fbcallback', {
template: "",
controller: 'fbCtrl'
}).
Angular controller:
app.controller("fbCtrl", function () {
window.history.back();
});
You could probably do some other client side routing in the controller as well.