Facebook is undoubtedly the biggest social network in the world with more than 2.7 billion registered and active users. If your web application provides the option to authenticate users with their Facebook data, then your entire registration and login process becomes a lot easier. Let’s learn how to implement user authentication with Facebook.

How to create a Facebook App ID and Secret Key

Go to Facebook for Developers, log into your account and click on My Apps in the navigation bar. Click on the Create App button, choose “Build Connected Experiences” and continue. create-app

Give your app a display name and a contact email, then create the app. create-app

On the next screen, fill in the App Domains, Privacy Policy URL and Terms of Service URL. Select a Category and an App Purpose, then Save Changes.

create-app

On the side menu, click on PRODUCTS + and set up Facebook Login. Select Web on the next screen.

create-app

The next information to specify is your Site URL and Save.

create-app

On the side menu, click on the Settings that is under Facebook Login. You are expected to provide at least one Valid OAuth Redirect URI. It’s also important to note that a http://localhost/ kind of URI will not be accepted as valid. I’ll give more information on the localhost set up shortly.

create-app

Finally, switch the status button from “In development” mode to “Live” mode if you are able to provide all criteria needed by Facebook for your app to approved. When your app is in ‘Live’ mode, you have permission to request a wide range of user data without any restrictions. However, if you are planning to test your implementation on your localhost, then do well to leave it ‘In development’ mode. The only challenge with this mode is that you cannot request any more than email, fullname, firstname, and lastname. You can access your App ID and App Secret at any time by going to Settings >> Basic.

Create a Project Directory

Make a directory and call it social_login or anything else you like. Within the directory, create two new folders and name them config-files and users. Create another folder within the root directory and name it facebook-login-client.

In order to download the Facebook graph SDK needed for our user authentication, navigate into facebook-login-client from your terminal and run the command below;

$ composer require facebook/graph-sdk

Set up a Database with MySQL

Create a database and call it social_systems. Before we create a table for the Facebook user’s profile data, we need to remember that apps in development mode cannot request the profile image of a user. Therefore, we have to set a default value of a John Doe/Jane Doe avatar in our table to make up for the profile image we won’t have access to.

Run the SQL commands you have below in your MySQL console.

/** MySQL console*/
USE social_systems;
CREATE TABLE facebook_users (
  id int(11) NOT NULL AUTO_INCREMENT,
  facebook_id varchar(255) NOT NULL,
  name varchar(150) NOT NULL,
  email varchar(150) NOT NULL,
  profile_image text DEFAULT 'https://images.opencollective.com/jane-doe/avatar/256.png',
  primary key (id),
  unique key facebook_id (facebook_id)
);

Code Implementation

There are file paths to indicate the files where every code snippet should be placed, and where every file should be placed in the different folders.

config-files/config.php
<?php
/*
 * Basic Site Settings and API Configuration
 */
// Database configuration
define('DB_HOST', 'localhost');
define('DB_USERNAME', '[YOUR USERNAME]');
define('DB_PASSWORD', '[YOUR PASSWORD, IF ANY]');
define('DB_NAME', '[YOUR DATABASE NAME]');

// Google API configuration
define('FACEBOOK_CLIENT_ID', '[YOUR ID]');
define('FACEBOOK_CLIENT_SECRET', '[YOUR SECRET]');
define('FACEBOOK_REDIRECT_URL', 'http://localhost/social_login/index.php');
config-files/Database.php
<?php
// Include configuration file
require_once('config.php');

class Database {
  // Define database parameters
  private $db_host = DB_HOST;
  private $db_name = DB_NAME;
  private $username = DB_USERNAME;
  private $password = DB_PASSWORD;
  private $cnxn;

  // Connect to database
  public function connect() {
    $this->cnxn = new mysqli($this->db_host, $this->username, $this->password, $this->db_name);
    if($this->cnxn->connect_error) {
      die('Cannot connect to database: &#37;s'. $this->cnxn->connect_error);
    }
    return $this->cnxn;
  }

  public function disconnectDB() {
    $this->cnxn = null;
  }
}
users/User.php
<?php
class User {
  // Database related data
  private $cxn;
  private $facebook_account_table = 'facebook_users';

  // Facebook User Properties
  public $id;
  public $name;
  public $email;
  public $profile_image;
  public $facebook_id;

  // Define a constructor
  public function __construct($connect_db) {
    $this->cxn = $connect_db;
  }

  // Facebook Login
  public function facebook_login($fbdata = array()) {
    if(!empty($fbdata)){
      $this->facebook_id = $this->cxn->real_escape_string($fbdata['facebook_id']);
      $this->name = $this->cxn->real_escape_string($fbdata['name']);
      $this->email = $this->cxn->real_escape_string($fbdata['email']);

      $fbUser = "SELECT `facebook_id` FROM " . $this->facebook_account_table . " WHERE facebook_id = '".$this->facebook_id."'";
      $fbUserResult = $this->cxn->query($fbUser);

      if($fbUserResult->num_rows > 0) {
        // return $execute_get_user->fetch_assoc();
        $fbUserUpdate = "UPDATE " . $this->facebook_account_table . " SET name = '" . $this->name ."' AND email = '" . $this->email ."'";
        $updatedFbUserResult = $this->cxn->query($fbUserUpdate);
      } else {
        // Add user to the database
        $this->facebook_id = $this->cxn->real_escape_string($fbdata['facebook_id']);
        $this->name = $this->cxn->real_escape_string($fbdata['name']);
        $this->email = $this->cxn->real_escape_string($fbdata['email']);

        $newFbUser = "INSERT INTO ". $this->facebook_account_table . " (`facebook_id`, `name`, `email`) VALUES('" . $this->facebook_id. "','" . $this->name. "','" . $this->email . "')";
        $newFbUserResult = $this->cxn->query($newFbUser);
      }
    } else {
      header('Location: errorpage.php');
      exit();
    }
    return $fbUserResult->fetch_assoc();
  }
}
facebook-login-client/googlelogin.php
<?php

require_once('vendor/autoload.php');
require_once('users/User.php');
require_once('config-files/Database.php');

$database = new Database();
$connection = $database->connect();

$fbUser = new User($connection);

// Facebook API Library
use Facebook\Facebook;
use Facebook\Exceptions\FacebookResponseException;
use Facebook\Exceptions\FacebookSDKException;

$fb = new Facebook(
    array(
      'app_id' => FACEBOOK_APP_ID,
      'app_secret' => FACEBOOK_APP_SECRET,
      'default_graph_version' => 'v3.2',
      )
    );

// The redirect login helper
$helper = $fb->getRedirectLoginHelper();

try {
  if(isset($_SESSION['access_token'])) {
    $accessToken = $_SESSION['access_token'];
  } else {
    $accessToken = $helper->getAccessToken();
  }
} catch(FacebookResponseException $e) {
  echo 'Graph returned an error" ' . $e->getMessage();
  exit();
} catch(FacebookSDKException $e) {
  echo 'Facebook SDK returned an error: ' . $e->getMessage();
  exit();
}

if(isset($_GET['code'])) {
  if(isset($accessToken)) {
    if(isset($_SESSION['access_token'])) {
      $fb->setDefaultAccessToken($_SESSION['access_token']);
    } else {
      $_SESSION['access_token'] = (string) $accessToken;
      $getClient = $fb->getOAuth2Client();
      $longAccessToken = $getClient->getLongLivedAccessToken($_SESSION['access_token']);
      $_SESSION['access_token'] = (string) $longAccessToken;
      $fb->setDefaultAccessToken($_SESSION['access_token']);

      // Get user profile data from Facebook
      try {
        $graphResponse = $fb->get('/me?fields=name,email');
        $userProfile = $graphResponse->getGraphUser();
      } catch(FacebookResponseException $e) {
        echo 'Graph returned an error: ' . $e->getMessage();
        session_destroy();
        header("Location: errorpage.php");
        exit;
      } catch(FacebookSDKException $e) {
        echo 'Facebook SDK returned an error: ' . $e->getMessage();
        exit;
      }

      $user_data = array();
      $user_data['facebook_id'] = !empty($userProfile['id']) ? $userProfile['id'] : '';
      $user_data['name'] = !empty($userProfile['name']) ? $userProfile['name'] : '';
      $user_data['email'] = !empty($userProfile['email']) ? $userProfile['email'] : '';

      $result = $fbUser->facebook_login($user_data);
      if($result) {
        extract($result);
        $_SESSION['facebook_user_id'] = $facebook_id;
        header('location: index.php');
        exit();
      }
    }
  } else {
    header('Location: errorpage.php');
    exit();
  }
} else {
  // Get login permission
  $permissions = ['email'];
  $facebookAuthUrl = $helper->getLoginUrl(FACEBOOK_REDIRECT_URL, $permissions);
  // Render Facebook login button
  $facebookButton = '<button><a href="'.htmlspecialchars($facebookAuthUrl).'" id="facebook" name="facebook">Login with Facebook</a></button>';
}

A look at some of the things that are happening in the facebook-login-client/googlelogin.php file.

use Facebook\Facebook;
use Facebook\Exceptions\FacebookResponseException;
use Facebook\Exceptions\FacebookSDKException;

These files are included in the file to allow access to the Facebook SDK and it’s exception handlers. We created an instance of the Facebook class in $fb, and used it to access all it’s relevant methods.Ultimately, we use the get() and getGraphUser() methods to retrieve the user’s profile information and proceed to save it to the database through the User class object.

users/facebookdata.php
<?php
require_once('facebook-login-client/facebooklogin.php');
require_once('users/User.php');
require_once('config-files/Database.php');

$database = new Database();
$connection = $database->connect();

$fb_id = $_SESSION['facebook_user_id'];

$user_data = "SELECT * FROM `fb_users` WHERE `facebook_id` = '$fb_id'";
$query_user_data = $connection->query($user_data);

if($query_user_data->num_rows > 0) {
  $result_object = $query_user_data->fetch_assoc();
} else {
  header('Location: logout.php');
  exit();
}
loginform.php
<?php
session_start();
require_once('facebook-login-client/facebooklogin.php');
?>
<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style>
    .btn-group button {
      background-color: #ffffff;
      border: 1px solid brown;
      padding: 10px 24px;
      cursor: pointer;
      float: left;
    }

    #google {color: red;}
    #facebook {color: blue}
    #twitter {color: lightblue}

    a {text-decoration: none;}

    /* Clear floats (clearfix hack) */
    .btn-group:after {
      content: "";
      clear: both;
      display: table;
    }

    .btn-group button:not(:last-child) {
      border-right: none; /* Prevent double borders */
    }

    /* Add a background color on hover */
    .btn-group button:hover {
      background-color: seashell;
    }
  </style>
</head>
<body>
  <h2>Social Login Button</var></h2>
  <p>&nbsp;</p>
  <div class="btn-group">
    <?php echo $facebookButton; ?>
  </div>
</body>
</html>
index.php
<?php
session_start();
if(isset($_SESSION['facebook_user_id'])) {
  require_once('users/facebookdata.php');
} else {
  header('Location: loginform.php');
  exit();
}
?>
<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <style>
    body, html {
      height: 100%;
      margin: 0;
      font-family: Arial, Helvetica, sans-serif;
    }

    .hero-image {
      background-image: linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url("https://iso.500px.com/wp-content/uploads/2014/07/big-one.jpg");
      height: 50%;
      background-position: center;
      background-repeat: no-repeat;
      background-size: cover;
      position: relative;
    }

    .hero-text {
      text-align: center;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: white;
    }

    .hero-text button {
      border: none;
      outline: 0;
      display: inline-block;
      padding: 10px 25px;
      color: black;
      background-color: #ddd;
      text-align: center;
      cursor: pointer;
    }

    .hero-text button:hover {
      background-color: #555;
      color: white;
    }

    .avatar {
      vertical-align: middle;
      width: 80px;
      height: 80px;
      border-radius: 50%;
    }
  </style>
</head>
<body>

  <div class="hero-image">
    <div class="hero-text">
      <h1 style="font-size:50px">I am <?php echo $result_object['name']; ?></h1>

      <?php if(isset($result_object['email'])){ ?>
        <p>My email is <?php echo $result_object['email']; ?></p>
      <?php }?>

      <img src="<?php echo $result_object['profile_image']; ?>" alt="<?php echo $result_object['name']; ?>" class="avatar">
    </div>
  </div>
  <a href="logout.php">Logout..</a>
</body>
</html>
logout.php
<?php
// Initialize the session.
if(!session_id()){
    session_start();
}

// Remove user data from session
unset($_SESSION['facebook_user_id']);

// Finally, destroy the session.
session_destroy();
header("Location: loginform.php");
exit();
errorpage.php
<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body>
    <h1>An Error Happened!</h1>
    <a href="loginform.php"><var>Return Back</var></a>
  </body>
</html>

Conclusion

It is not possible to use the App ID and Secret of a Facebook app that is already in “Live” mode to test your code on localhost. Facebook practically rejects every non-secured Redirect URI that has HTTP instead of HTTPS.

Find the sequel to this article in Social Media Login with Twitter, PHP and MySQL.