skip to Main Content

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.js
to 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);

4

Answers


  1. 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.

    Login or Signup to reply.
  2. 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.

    Login or Signup to reply.
  3. 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.

    Login or Signup to reply.
  4. 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);
    }));
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search