0
votes

Been having some trouble for the past week getting this link to work. Feel like I'm misunderstanding something from the flow.

What I'm struggling with was implementing the passport with passport-facebook. I want to include the passport.authenticate inside the same route as the account linking. Currently only managed to separate the two processes and having two logins. Looking to merge them. As can be seen here http://recordit.co/osdMl0MUCL

Is there no way to do the passport.authenticate inside the link route ? Been trying with no success. Tried to move the passport.authenticate inside app.get('/authorize but don't know how to handle the const redirectURISuccess = ${redirectURI}&authorization_code=${authCode}; res.redirect(redirectURISuccess);

I'm thinking would need to do this inside the app.get(/auth/fb/callback' ... but not sure how.

This is what I have currently

'use strict';
require('dotenv').config();

const express = require('express');
const router = express.Router();
const bodyParser = require('body-parser');

const http = require('http');
const port = '3000';

const passport = require('passport');
const FacebookStrategy = require('passport-facebook').Strategy;
const fbConfig = require('./oauth');
const cookieParser = require('cookie-parser');
const session = require('express-session');
    // used to serialize the user for the session
    // Not using these yet
passport.serializeUser(function (user, done) {
  done(null, user.id);
});

passport.deserializeUser(function (obj, done) {
  done(null, obj);
});

const Botly = require('botly');
const botly = new Botly({
  accessToken: process.env.ACCESS_TOKEN,
  verifyToken: '123123321' // the verification token you provided when defining the webhook in facebook
});

const app = express();

// Listen on the account link event
botly.on('account_link', (sender, message, link) => {
    // Continue conversation
  console.log('CONFIRMED AUITH', link);
  botly.sendText({
    id: sender,
    text: (link.status === 'unlinked') ? 'sorry to see you go' : 'Welcome'
  });
  botly.sendButtons({
    id: sender,
    text: 'Please Login Again :-) This time for real',
    buttons: [ botly.createAccountLinkButton(`https://${process.env.LOGIN_DOMAIN}/auth/fb/?senderId=' + sender/`) ]
  });
});
botly.on('message', (senderId, message, data) => {
  const text = `echo: ${data.text}`;

  botly.sendText({
    id: senderId,
    text: text
  });
  botly.sendButtons({
    id: senderId,
    text: 'Please Login :)',
    buttons: [ botly.createAccountLinkButton(`https://${process.env.LOGIN_DOMAIN}/authorize/`), botly.createAccountUnLinkButton() ]
  });
});

app.use(bodyParser.json());
app.use('/', router);

app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({ secret: 'its_my_secret', resave: true, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
app.use('/webhook', botly.router());
app.set('port', port);

/*
 * This path is used for account linking. The account linking call-to-action
 * (sendAccountLinking) is pointed to this URL.
 *
 */
app.get('/authorize', function (req, res) {
  // Passport setup
  passport.use('facebook', new FacebookStrategy({
    clientID: fbConfig.facebook.clientID,
    clientSecret: fbConfig.facebook.clientSecret,
    callbackURL: fbConfig.facebook.callbackURL,
    profileFields: [ 'id', 'displayName', 'email' ]

  },

  // facebook will send back the tokens and profile
  function (request, access_token, refresh_token, profile, done) {
    // asynchronous
    process.nextTick(function () {
      console.log('WATCH THIS: ', profile);
      return done(null, profile);
    });
  }));
  console.log('%%%%%%%% AccountLinking Testing');

  const accountLinkingToken = req.query.account_linking_token;
  const redirectURI = req.query.redirect_uri;

  console.log('%%%%%%%% /authorize called with accountLinkingToken %s, redirectURI %s', accountLinkingToken, redirectURI);

  // Authorization Code should be generated per user by the developer. This will
  // be passed to the Account Linking callback.
  const authCode = '1234567890';

  // Redirect users to this URI on successful login
  const redirectURISuccess = `${redirectURI}&authorization_code=${authCode}`;
  res.redirect(redirectURISuccess);
});

app.get('/auth/fb', (req, res, next) => {
  req.session.senderId = req.query.senderId;
  passport.authenticate('facebook', { scope: [ 'email' ] },
    {
      state: {
        senderId: req.query.senderId // senderId will be used after auth to reply to the user
      }
    })(req, res, next);
});

        // Redirection after login
app.get('/auth/fb/callback',
passport.authenticate('facebook', {
  successRedirect: `https://m.me/${process.env.app_name}`, // The webview I want to open if user logs in
  failureRedirect: '/somePage' // redirect to Messenger if failure
}));

const server = http.createServer(app);
server.listen(port);
1

1 Answers

0
votes

I solved it I think. Probably not the best way to go about it though. I'm passing the account linked redirect URI to the callback route and resolving the passport.authenticate in there redirecting if needed.

'use strict';
require('dotenv').config();

const express = require('express');
const router = express.Router();
const bodyParser = require('body-parser');
const LINKED = {};

const http = require('http');
const port = '3000';

const passport = require('passport');
const FacebookStrategy = require('passport-facebook').Strategy;
const fbConfig = require('./oauth');
const cookieParser = require('cookie-parser');
const session = require('express-session');
    // used to serialize the user for the session
    // Not using these yet
passport.serializeUser(function (user, done) {
  done(null, user.id);
});

passport.deserializeUser(function (obj, done) {
  done(null, obj);
});

const Botly = require('botly');
const botly = new Botly({
  accessToken: process.env.ACCESS_TOKEN,
  verifyToken: '123123321' // the verification token you provided when defining the webhook in facebook
});

const app = express();

// Listen on the account link event
botly.on('account_link', (sender, message, link) => {
    // Continue conversation
  console.log('CONFIRMED AUITH', link);
  botly.sendText({
    id: sender,
    text: (link.status === 'unlinked') ? 'sorry to see you go' : 'Welcome'
  });
});
botly.on('message', (senderId, message, data) => {
  const text = `echo: ${data.text}`;

  botly.sendText({
    id: senderId,
    text: text
  });
  botly.sendButtons({
    id: senderId,
    text: 'Please Login :)',
    buttons: [ botly.createAccountLinkButton(`https://${process.env.LOGIN_DOMAIN}/authorize/?senderId=' + senderId/`), botly.createAccountUnLinkButton() ]
  });
});

app.use(bodyParser.json());
app.use('/', router);

app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({ secret: 'its_my_secret', resave: true, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
app.use('/webhook', botly.router());
app.set('port', port);

  // Passport setup
passport.use('facebook', new FacebookStrategy({
  clientID: fbConfig.facebook.clientID,
  clientSecret: fbConfig.facebook.clientSecret,
  callbackURL: fbConfig.facebook.callbackURL,
  profileFields: [ 'id', 'displayName', 'email' ]

},

  // facebook will send back the tokens and profile
  function (request, access_token, refresh_token, profile, done) {
    // asynchronous
    process.nextTick(function () {
      return done(null, profile);
    });
  }));

/*
 * This path is used for account linking. The account linking call-to-action
 * (sendAccountLinking) is pointed to this URL.
 *
 */
app.get('/authorize', function (req, res, next) {
  req.session.senderId = req.query.senderId;

  console.log('%%%%%%%% AccountLinking Testing');

  const accountLinkingToken = req.query.account_linking_token;
  const redirectURI = req.query.redirect_uri;

  console.log('%%%%% /authorize called with accountLinkingToken %s, redirectURI %s', accountLinkingToken, redirectURI);

  // Authorization Code should be generated per user by the developer. This will
  // be passed to the Account Linking callback.
  const authCode = '1234567890';
  // Redirect users to this URI on successful login
  const redirectURISuccess = `${redirectURI}&authorization_code=${authCode}`;
  LINKED.redirect = redirectURISuccess;
  console.log('redirect to this ', redirectURISuccess);
  passport.authenticate('facebook', { scope: [ 'email' ] },
    {
      state: {
        senderId: req.query.senderId // senderId will be used after auth to reply to the user
      }
    })(req, res, next);
});

        // Redirection after login
app.get('/auth/fb/callback', (req, res, next) => {
  passport.authenticate('facebook', (err, user, info) => {
    if (err) { return next(err); }
    if (!user) {
      console.log('bad', info);
      return res.redirect(LINKED.redirect);
    }
    console.log('good');
    LINKED.user = user;
  })(req, res, next);
  res.redirect(LINKED.redirect);
});

const server = http.createServer(app);
server.listen(port);