How to implement Facebook Sign In with Express.js

Updated: December 30, 2023 By: Guest Contributor Post a comment

Integrating Facebook Sign In into an Express.js application enables users to log in using their Facebook credentials, providing a convenient and secure authentication flow. In this article, we’ll walk through the process of adding Facebook authentication to your Express.js application using the latest Node.js and JavaScript features such as arrow functions, async/await, and ES modules.

Initial Setup

Before you begin, ensure that you have Node.js installed on your system and that you’re familiar with the basics of Express.js. If you don’t have an Express.js project already set up, start by creating a new project and an Express.js app. You’ll also need to register your application with Facebook for Developers to obtain the App ID and App Secret required for OAuth integration.

Installing Necessary Packages

Start by installing ‘passport’, ‘passport-facebook’, and ‘express-session’ packages using npm:

npm install passport passport-facebook express-session

Setting up Express Session

Configure express-session which is required to maintain session data for authenticated users:

import session from 'express-session';
import express from 'express';

const app = express();
app.use(session({
  secret: 'your_secret_key',
  resave: false,
  saveUninitialized: true
}));

Configuring Passport

Set up passport with the Facebook strategy and include your Facebook App ID and Secret:

import passport from 'passport';
import { Strategy as FacebookStrategy } from 'passport-facebook';

const FACEBOOK_APP_ID = 'your_facebook_app_id';
const FACEBOOK_APP_SECRET = 'your_facebook_app_secret';

passport.use(new FacebookStrategy({
  clientID: FACEBOOK_APP_ID,
  clientSecret: FACEBOOK_APP_SECRET,
  callbackURL: "http://localhost:3000/auth/facebook/callback"},
  async (accessToken, refreshToken, profile, done) => {
    // In a production app, you would save profile information to your database here.
    // For simplicity, we'll just pass the profile object forward.
    return done(null, profile);
  }
));

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

passport.serializeUser((user, done) => {
  done(null, user);
});

passport.deserializeUser((user, done) => {
  done(null, user);
});

Implementing Routes for Authentication

Create route handlers for the log in process and the OAuth callback:

app.get('/auth/facebook', passport.authenticate('facebook'));
app.get('/auth/facebook/callback',
  passport.authenticate('facebook', { failureRedirect: '/login' }),
  (req, res) => {
    // Successful authentication, redirect to your desired page
    res.redirect('/');
  }
);

Creating the Testing Route

Add a route that displays the user object as a simple means to test the authentication:

app.get('/', (req, res) => {
  if (req.isAuthenticated()) {
    res.json(req.user);
  } else {
    res.send('Not authenticated');
  }
});

Listening to the Server

Finally, set your Express application to listen on a port:

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server is running on port ${PORT}`));

Complete Code Example

The final code structure should be similar to the excerpts shown above, and the entire application file would look as follows:

// Import necessary modules
import express from 'express';
import session from 'express-session';
import passport from 'passport';
import { Strategy as FacebookStrategy } from 'passport-facebook';

// Facebook App credentials
const FACEBOOK_APP_ID = 'your_facebook_app_id';
const FACEBOOK_APP_SECRET = 'your_facebook_app_secret';

// Create an Express application
const app = express();

// Configure express-session
app.use(session({
    secret: 'your_secret_key',
    resave: false,
    saveUninitialized: true
}));

// Passport setup with Facebook Strategy
passport.use(new FacebookStrategy({
    clientID: FACEBOOK_APP_ID,
    clientSecret: FACEBOOK_APP_SECRET,
    callbackURL: "http://localhost:3000/auth/facebook/callback"
  },
  async (accessToken, refreshToken, profile, done) => {
    // In a production app, save profile information to your database here
    return done(null, profile);
  }
));

// Initialize Passport and restore authentication state, if any, from the session
app.use(passport.initialize());
app.use(passport.session());

// Serialize user
passport.serializeUser((user, done) => {
    done(null, user);
});

// Deserialize user
passport.deserializeUser((user, done) => {
    done(null, user);
});

// Define routes
app.get('/auth/facebook', passport.authenticate('facebook'));

app.get('/auth/facebook/callback',
    passport.authenticate('facebook', { failureRedirect: '/login' }),
    (req, res) => {
        // Successful authentication, redirect home
        res.redirect('/');
    }
);

// Testing route to display the user object
app.get('/', (req, res) => {
    if (req.isAuthenticated()) {
        res.json(req.user);
    } else {
        res.send('Not authenticated');
    }
});

// Start the server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

In this code:

  1. Facebook authentication strategy is set up with Passport.
  2. Express sessions are configured to maintain session state.
  3. Routes are defined for initiating Facebook authentication and handling the callback.
  4. A test route is created to verify the authentication status and display user info.
  5. The server is started on a specified port.

Remember to replace your_facebook_app_id, your_facebook_app_secret, and your_secret_key with your actual Facebook app credentials and a secret key for your session.

This example provides a basic implementation. In a real-world application, you would need to handle user data storage and more comprehensive error handling.

Conclusion

By following the steps above, you’ll have a functioning Express.js server that allows users to authenticate using their Facebook account. This guide merely scratches the surface of what’s possible with Passport’s strategy ecosystem. The same concept can be applied to integrate various other OAuth providers into your application.