nodejs backbone and passportjs - node.js

i am using nodejs (with express) and backbone. I would like to integrate passport.js for facebook authentication.
I have the following route:
app.get('/auth/facebook', passport.authenticate('facebook', { scope: [ 'email', 'user_about_me'], failureRedirect: '/login' }), users.signin);
What should I do in case the user logged in successfully? How can I access to the user data?
What should I do in case the user DID NOT log in successfully? How can I open the facebook dialog?
Are there any good examples of using passport.js with single page applications?

I know I am answering late but in case you haven't been able to figure out how to use facebook strategy of passport yet, you can go through example provided here.

I hope this is helpful for you :)
Here is the solution recently I have done the facebook connect with passport
I assume you install the passport modules
app.js
var passport = require('passport');
require('./lib/connect')(passport); // pass passport for configuration
routes.js
// send to facebook to do the authentication
app.get('/auth/facebook',
passport.authenticate('facebook', { scope : 'email' })
);
I have created a lib file
connect.js
var FacebookStrategy = require('passport-facebook').Strategy;
module.exports = function(passport) {
passport.use(new FacebookStrategy({
clientID : facebookAuth.clientID,
clientSecret : facebookAuth.clientSecret,
callbackURL : facebookAuth.callbackURL,
passReqToCallback : true // allows us to pass in the req from our route
},
function(req, token, refreshToken, profile, done) {
// here you can get the user profile info
console.log("profile : "+JSON.stringify(profile));
// asynchronous
process.nextTick(function() {
//your logic
});
});
};

Related

How can I test my Backend API against google Oauth2?

My goal is to create an authentication backend and I would like to implement google's Oauth2, and for that I decided to follow the passport documentation. My only issue is, how can I test this on my Postman? I'm just developing a backend and I don't know if it's working, I know it sounds a little silly but for a beginner like me it's a lot. Thanks
const dotenv = require('dotenv').config();
const express = require('express');
const passport = require('passport');
var GoogleStrategy = require('passport-google-oauth20').Strategy;
const app = express();
const port = process.env.PORT;
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "http://www.example.com/auth/google/callback"
},
function(accessToken, refreshToken, profile, cb) {
User.findOrCreate({ googleId: profile.id }, function (err, user) {
return cb(err, user);
});
}
));
app.get('/auth/google',
passport.authenticate('google', { scope: ['profile'] }));
app.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
try {
app.listen(port);
console.log(`Server starting on port ${port}`);
} catch (err) {
console.log(err);
}
Whichever OAuth2 service is pretty simply, if you step into it ;)
In first step you send client_id and client_secret to authorization uri.
In second step, the user authenticates with his credentials and you receive the code which you exchange with authorization server for token.
You make request with Bearer token.
Postman can handle some of the things for you. So:
In Google Dev Console create your credentials.
As callback uri fill in:
https://www.getpostman.com/oauth2/callback
https://oauth.pstmn.io/v1/callback
In Postman create new Collection and define following variables:
Define following Authorization:
When you click Get New Access Token you will be asked to login to Google and get back with token.
With this token you can use whichever service you have in scope and your project on Developer Console includes (look for Enabled APIs and services).
Example request:
Create new GET request and save it in your collection, so the variables and tokens are inherited.
URL is: https://www.googleapis.com/oauth2/v1/userinfo?alt=json
Auth in Postman: Inherit auth from parent.
And Send...
Took me months to understand, so hope you'll be swifter :)

Problem with facebook login using passport (Node.js Express)

I am following the code examples from the book "Node.js 8 the right way" by Jim R. Wilson.
In the book you are building a small application that allows you to sign in through Facebook (Using Passport.js)
Here is my code for setting up Passport middleware:
app.use(passport.initialize());
app.use(passport.session());
const FaceBookStrategy = require('passport-facebook').Strategy;
passport.use(new FaceBookStrategy({
clientID: nconf.get('auth:facebook:appID'),
clientSecret: nconf.get('auth:facebook:appSecret'),
callbackURL: new URL('/auth/facebook/callback', serviceUrl).href
},
(accessToken,refreshToken,profile,done) => done(null,profile)
));
app.get('/auth/facebook',passport.authenticate('facebook'));
app.get('/auth/facebook/callback', passport.authenticate('facebook', {
successRedirect: '/',
failureRedirect: '/'
}));
However when I try logging in, Facebook responds by saying that it only accepts logins from a safe site (https). Has something changed since this book was written, or do i need to set up my server to use https in order to use Facebook login?

Passport & SmartThings

This is going to be quite a broad question as I am stuck where to really start. I'm trying to authenticate with SmartThings using Passport. Looking at the SmartThings documentation here:
http://docs.smartthings.com/en/latest/smartapp-web-services-developers-guide/tutorial-part2.htm
SmartThings doesn't return any user information, simply an authentication token you then use to make calls to your SmartThings instance to control the environment.
I'm currently trying to use the OAuth2 Strategy, however this expects a user profile to be returned to serialise the user, which in this instance is null.
What I am trying to achieve is for someone to authorise with SmartThings and store their token in a session so that their data can be pulled.
Long term I will assign it to a user account local to my application, however for now, I'd just like to get the above working.
Does anyone know how I am best going about this. I am somewhat struggling with this.. perhaps using the OAuth2 Strategy isn't the right way to go about it? I currently have this:
var passport = require('passport');
var OAuth2Strategy = require('passport-oauth2').Strategy;
var verifyHandler = function(req, token, refreshToken, profile, done){
return done(token)
}
passport.serializeUser(function(user, done) {
done(null, user.id);
});
module.exports.http = {
customMiddleware: function(app) {
passport.use(new OAuth2Strategy({
authorizationURL: 'https://graph.api.smartthings.com/oauth/authorize',
tokenURL: 'https://graph.api.smartthings.com/oauth/token',
clientID: '123',
clientSecret: 'abc',
callbackURL: 'http://localhost:1337/auth/smartthings/callback',
skipUserProfile: true,
passReqToCallback: true
}, verifyHandler));
app.use(passport.initialize());
app.use(passport.session());
}
}
I think that what you want to do is this in the authentication process:
Authenticate the user in your application using the passport's local strategy
Manually generate SmartThings' authorization code and token - guide here
Save the token in user's session
After that you can use the token in session to make requests to SmartThings' API

PassportJS with Facebook strategy, is my code correct?

I use NodeJs with passportJS in my app to allow users to login/register using Facebook. It seems to work fine, not sure if I understand fully what is happening there though. So the idea is that users can try to login from different pages in my app using Facebook details. After Facebook returns me all the details I log them in or register new user using what Facebook returned and after this is done redirect them to same page but being already logged in. The code is:
var passport = require('passport'),
FacebookStrategy = require('passport-facebook').Strategy;
function setupFBStrategy(req, res, next) {
return function(req, res, next) {
var redirectUrl = req.params.currentPage;
console.log('setupFBStrategy')
passport.use(new FacebookStrategy({
clientID: 'abc',
clientSecret: 'def',
// step 2 ################################
callbackURL: "/auth/facebook/callback?currentPage="+redirectUrl,
passReqToCallback: true,
profileFields: ['first_name', 'last_name', 'photos', 'email']
},
function(req, accessToken, refreshToken, profile, done) {
// step 5 ###########################
// verify callback. Now I have user email inside 'profile' and I authenticate this aginst my database. I use `done(..)` to further instruct my app if the registration/authentication with my system was success or not
}
));
next();
}
}
app.use(passport.initialize());
// step 1 ################################
app.get('/auth/facebook/cp/:currentPage', setupFBStrategy(), passport.authenticate('facebook', { authType: 'rerequest', scope: ['email'] }));
app.get('/auth/facebook/callback',
function(req, res, next) {
console.log(req.query.currentPage)
passport.authenticate('facebook', {
successRedirect: '/'+req.query.currentPage, // redirects when user allowed or logged in with username password
failureRedirect: '/'+req.query.currentPage // takes here when user clicks cancel when asked to give permissions
})(req,res,next);
}
);
passport.serializeUser(function(user, done) {
console.log('serialize='+user)
done(null, {});
});
passport.deserializeUser(function(user, done) {
console.log('deserialize=' + user);
done(null, {});
});
The steps are:
in my app user clicks "login/register with facebook" that makes request to auth/facebook/cp route.
route calls setUpFBStrategy. I append current page user is looking at to callbackUrl.
PassportJS send redirect back to user browser and user browser redirects to facebook for authentication.
when facebook is finished authenticating user it sends redirect to user browser so the browser redirects to callbackURL with URL specified in step 2. It also appends '?code=' querystring to callback URL. Is this querystring hashed version of what Facebook returns so in my case public info and email?
Now my server 'auth/facebook/callback' is executed and verify callback is executed. Depending if I call done(null,profile) etc inside verify callback server returns redirect to browser and browser redirects to successRedirect or failureRedirect 'successRedirect' or 'failureRedirect' routes.
All seems to work so far but is my understanding correct? Is 'code' querystring hashed version of details facebook returns? Why do I even need serializeUser and deserializeUser functions in my code? When would I use refreshToken and accessToken?
yes your code seems to be fine.
passport.serializeUser and passport.deserializeUser and function provided by the passport
passport.serializeUser is called once on login when you call
req.logIn(someValue,function(){})
here someValue is the value you want to store in the passport session
and on every request when you call req.isAuthenticated() function to check that the passport session exist or not the passport.deserializeUser will be called returning true or false.
and in end of the user browsing means on logout you call req.session.destroy to destroy that perticular users session.

FacebookTokenError: This authorization code has been used

Ok, so this is a common error with many causes. I am trying to modify an existing Node-Passport-Facebook module to have local images from the desktop uploaded to a users Facebook account after they log in. That is my goal. This is the code module I am extending
https://github.com/passport/express-4.x-local-example
which in turn is based on
https://github.com/jaredhanson/passport-facebook
I never get past console.log('ERROR HERE... with an error of "This authorization code has been used."
What's confusing is that the auth code returned is ALWAYS DIFFERENT! so how could it already have been used when I try and exchange it for an access token?
Can anyone offer some suggestions, and or next steps I might try? My hunch is that there is something about Passport.js that is not implemented properly.
So my question is, how would I modify the code below (based on this passport facebook example) https://github.com/passport/express-4.x-facebook-example/blob/master/server.jsto upload an image after logging in?
var express = require('express');
var passport = require('passport');
var Strategy = require('passport-facebook').Strategy;
var CLIENTSECRET ='<client secret>';
var APPID ='<app id>';
// Configure the Facebook strategy for use by Passport.
//
// OAuth 2.0-based strategies require a `verify` function which receives the
// credential (`accessToken`) for accessing the Facebook API on the user's
// behalf, along with the user's profile. The function must invoke `cb`
// with a user object, which will be set at `req.user` in route handlers after
// authentication.
passport.use(new Strategy({
clientID: APPID,
clientSecret: CLIENTSECRET,
callbackURL: 'http://localhost:3000/login/facebook/return',
enableProof: true
//callbackURL: 'http://localhost:3000/login/facebook/return'
},
function(accessToken, refreshToken, profile, cb) {
// In this example, the user's Facebook profile is supplied as the user
// record. In a production-quality application, the Facebook profile should
// be associated with a user record in the application's database, which
// allows for account linking and authentication with other identity
// providers.
cb(null, profile);
}));
// Configure Passport authenticated session persistence.
//
// In order to restore authentication state across HTTP requests, Passport needs
// to serialize users into and deserialize users out of the session. In a
// production-quality application, this would typically be as simple as
// supplying the user ID when serializing, and querying the user record by ID
// from the database when deserializing. However, due to the fact that this
// example does not have a database, the complete Twitter profile is serialized
// and deserialized.
passport.serializeUser(function(user, cb) {
cb(null, user);
});
passport.deserializeUser(function(obj, cb) {
console.log(" ");
console.log("ASSERT passport.deserializeUser being called");
console.log(" ");
cb(null, obj);
});
// Create a new Express application.
var app = express();
// Configure view engine to render EJS templates.
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
// Use application-level middleware for common functionality, including
// logging, parsing, and session handling.
app.use(require('morgan')('combined'));
app.use(require('cookie-parser')());
app.use(require('body-parser').urlencoded({ extended: true }));
app.use(require('express-session')({ secret: 'keyboard cat', resave: true, saveUninitialized: true }));
// Initialize Passport and restore authentication state, if any, from the
// session.
app.use(passport.initialize());
//app.use(passport.session());
// Define routes.
app.get('/',
function(req, res) {
res.render('home', { user: req.user });
});
app.get('/login',
function(req, res){
res.render('login');
});
app.get('/login/facebook',
passport.authenticate('facebook'));
app.get('/login/facebook/return',
passport.authenticate('facebook', { failureRedirect: '/login' }),
function(req, res) {
//my code changes start here!!
var code = req.query.code;
console.log("1 ASSERT after successful login! code="+code);
if(req.query.error) {
// user might have disallowed the app
return res.send('login-error ' + req.query.error_description);
} else if(!code) {
return res.redirect('/');
}
var options={
host:'graph.facebook.com',
path:'/oauth/access_token?client_id='+APPID+'&code='+code +'&client_secret='+CLIENTSECRET+'&redirect_uri=http://localhost:3000/login/faceboo k/return'
}
var https=require('https');
https.get(options,function(res){
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('ERROR HERE'+chunk);
});
});
console.log("2 ASSERT after successful login!")
//my code changes end here!!
});
app.get('/profile',
require('connect-ensure-login').ensureLoggedIn(),
function(req, res){
res.render('profile', { user: req.user });
});
app.listen(3000);
You don't need to make a request to /oauth/access_token at all (well you do, but passport has already handled it for you). That endpoint is for getting an access token when you don't have one, but you already have an access token here:
passport.use(new Strategy({
clientID: APPID,
clientSecret: CLIENTSECRET,
callbackURL: 'http://localhost:3000/login/facebook/return',
enableProof: true
//callbackURL: 'http://localhost:3000/login/facebook/return'
},
function(accessToken, refreshToken, profile, cb) {
// You have the access token here!
cb(null, profile);
}));
You'll need to save that accessToken some way, so that you can use it later when you make requests to the Graph API. You'll probably want to save it to the user's session, but you can also use a strategy like this: https://stackoverflow.com/a/24474900/772035
If you want the user to grant permission to publish (which you will need them to do, to be able to post to their feeds) you also need to replace every call to passport.authenticate with:
passport.authenticate('facebook', { scope: ['publish_actions'] } );
So that the posting permission is requested when the user first adds your app. Then you'll be able to use the /user/photos endpoint to upload a photo, passing the accessToken that you saved earlier in the query string.
You need to encode your query params.
var qs = {
client_id: APPID,
redirect_uri: 'http://localhost:3000/login/facebook/return',
client_secret: CLIENTSECRET,
code: code,
};
options = {
host:'graph.facebook.com',
path:'/oauth/access_token?' + require('querystring').stringify(qs),
};
I think that's your problem. The code itself looks fine apart from that. You'll want the querystring module to parse the results too by the way.
I solved this error. Follow the progress.
Facebook Log in -> Settings -> Apps -> Logged in with Facebook -> Delete Your apps.
After deleting your apps, Try to login with Facebook button.
you need to define profileFields instead of enableProof: true
passport.use(new FacebookStrategy({
clientID:keys.FacebookAppID,
clientSecret:keys.FacebookAppSecret,
callbackURL:'http://localhost:3000/auth/facebook/callback',
profileFields:['email','name','displayName','photos']
},(accessToken,refreshToken,profile,done)=>{
console.log(profile);
}));

Resources