Yes, there are a lot of posts regarding Facebook login with passport.js. But, I didn’t find anything where the frontend and backend are on different servers, like React as frontend, and Node.js as Backend. That costs me a lot of time. Hopefully, this post will save you some time.

In this article we’ll use:

  • React as Frontend (you can use anything)
  • Node.js as Backend (express)
  • Passport.js as Facebook Login strategy

The full source code is available here.

Configure the Backend

Run yarn init -y to initialize package.json. Then, install expresspassport, and passport-facebook by running this command:

yarn add express express-session passport passport-facebook

Install other utilities with:

yarn add cookie-parser body-parser

And finally, copy and paste the full code of the backend Server:

const express = require('express');
const app = express();
const port = 8080;
const passport = require('passport');
const Strategy = require('passport-facebook').Strategy;
const config = require('./config');

passport.use(new Strategy({
  clientID: config.FACEBOOK_CLIENT_ID,
  clientSecret: config.FACEBOOK_CLIENT_SECRET,
  callbackURL: '/facebook/callback'
},
function(accessToken, refreshToken, profile, cb) {
  // save the profile on the Database
  // Save the accessToken and refreshToken if you need to call facebook apis later on
  return cb(null, profile);
}));

passport.serializeUser(function(user, cb) {
  cb(null, user);
});

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

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 }));

app.use(passport.initialize());
app.use(passport.session());

app.get('/facebook', passport.authenticate('facebook'));
app.get('/facebook/callback', passport.authenticate('facebook', { failureRedirect: `${config.FRONTEND_HOST}/error`}), (req, res) => {
  res.send(`${config.FRONTEND_HOST}/success`);
}) ;

app.listen(port, () => {
  console.log(`App is listening on ${port}`);
})

Now let’s go through the code line by line:

const express = require('express');
const app = express();
const port = 8080;
const passport = require('passport');
const Strategy = require('passport-facebook').Strategy;
const config = require('./config');

The part above imports all the libraries and the config files.

The part below is the config file where I have set all the environment variables:

module.exports = {
  FRONTEND_HOST: '', 
  FACEBOOK_CLIENT_ID: '',
  FACEBOOK_CLIENT_SECRET: '',
}

FROTEND_HOST is the domain name of your frontend
FACEBOOK_CLIENT_ID is the client ID of your Facebook app
FACEBOOK_CLIENT_SECRET is the client secret of your Facebook app

passport.use(new Strategy({
  clientID: config.FACEBOOK_CLIENT_ID,
  clientSecret: config.FACEBOOK_CLIENT_SECRET,
  callbackURL: '/facebook/callback',
  profileFields: ['id', 'displayName', 'email', 'name', 'photos'],
  passReqToCallback: true,
},
function(req, accessToken, refreshToken, profile, cb) {
  // save the profile on the Database
  // Save the accessToken and refreshToken if you need to call facebook apis later on
  return cb(null, profile);
}));

Above, I have configured the Facebook strategy. callbackURL is the URL which will be called after authentication.profileFields are the pieces of information we want to be returned from Facebook, and passReqToCallback says the req param to be present on the callback function.

On the callback function, we will get:

  • req param from the get call
  • accessToken is used to call Facebook API next time, it can be used once
  • refreshToken is used to get the new accessToken
  • profile is the param where we will get the information of the user
  • cb is a callback function, MUST be called at the end of this function
passport.serializeUser(function(user, cb) {
  cb(null, user);
});
passport.deserializeUser(function(obj, cb) {
  cb(null, obj);
});

These two functions are used to serialize and deserialize the pieces of information passed from the Facebook callback function.

app.use(passport.initialize());
app.use(passport.session());

passport.initialize() is used to initialize the passport authentication
passport.session() is used to initialize the passport session

app.get('/facebook', passport.authenticate('facebook'));
app.get('/facebook/callback', passport.authenticate('facebook', { failureRedirect: `${config.FRONTEND_HOST}/error`}), (req, res) => {
  res.send(`${config.FRONTEND_HOST}/success`);
}) ;

First, the /facebook endpoint is called from the frontend. Second, the /facebook/callback endpoint is called from Facebook after authentication.

And that’s it for the Backend part. Easy, right? 🤔

Configure the Frontend

Use create-react-app to initialize a simple react app:

yarn create react-app frontend

I have kept the Frontend part real simple. Just add the anchor tag to call http://localhost:8080 and that’s it. Everything will work on backend and return to the URL res.send(`${config.FRONTEND_HOST}/success`);.

That’s it! The Frontend part is complete.

Configure the FaceBook app

Now, let’s configure the Facebook app and get ClientId & ClientSecret.

  1. Add a new app from here
  2. Go to Settings → Basic
  3. You will get the Client ID and Client Secret here

4. On the left side of the bar, click on the + sign beside products

5. Select Facebook LogIn setup

6. You don’t have to do anything here, passport.js has done everything for you

7. Go to the settings on Facebook Login

8. Set up the app like the above image. You must add the redirect URI as described on the backend.

9. Go to the app settings and add localhost as an app domain

That’s it! Everything should work as expected.

Leave a Reply