Implementing user login with Twitter is a bit complicated because it requires a number of steps to authentication. In this article, you will learn one of the few available solutions that will definitely work.

How to get a Twitter App, API Key and Secret Key

If you do not already have one, the first thing you need to do is apply here for a Twitter Developer account. While you wait for your request to be approved and granted, you can log into Twitter and make sure you add your mobile number to your Account information by clicking on this link.

When you click the approval link from Twitter, give a name to your App and get the keys.

twitter-app

Skip to your dashboard. Copy all the keys and keep them safe as you will be needing them later. They are also known as your Consumer Keys.

twitter-app

Locate your Project App settings on the dashboard.

twitter-app

Edit App Details to add a description, while in App permissions, choose either Read and Write or Read + Write + Direct Messages.

Edit Authentication settings by switching on Enable 3-legged OAuth and Request email address from users. You are also mandated to provide a Website URL, a Callback URL, a Terms of serviceURL and a Privacy policy URL.

twitter-app

Finally, switch to Keys and Tokens. Click the Generate button for Access token and secret. These are important because every login request will have to call up these tokens. At this point, you have a set of Consumer Keys and a set of Authentication Tokens.

twitter-app

The Project Directory

Just like we did in the first two parts of our social media login series, create a root directory and name it twitterlogin. Right inside the same directory, create two new folders and respectively name them twitter and twitter-api.

Still in the root directory of your application, create the following files:

A config.php

B index.php

C loginform.php

D logout.php

E errorpage.php

F twitteroauthcallback.php

On your terminal, change directory(cd) into the twitter folder and run the command below;

$ composer require abraham/twitteroauth

The command would have downloaded the Twitter API containing a vendor folder, a composer.json file and a composer.lock file.

Create a Database

Using your MySQL console, run the following commands to create a database(social_system) and a table(twitter_users);

/** MySQL console*/
create database social_systems;
use social_systems;

create table twitter_users (
  id int(11) not null auto_increment,
  twitter_id varchar(150) not null,
  name varchar(50) not null,
  email varchar(50) not null,
  profile_image text not null,
  primary key (id),
  unique key twitter_id (twitter_id)
);

App Configuration

In the config.php, we’ll provide configuration values for the database and the Twitter API.

config.php

<?php
/*
 * Basic Site Settings and API Configuration
 */

// Database configuration
define('DB_HOST', 'localhost');
define('DB_USERNAME', 'root');
define('DB_PASSWORD', '');
define('DB_NAME', 'social_system');

$conn = mysqli_connect(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME);

// Twitter OAuth configuration
define('TWITTER_CONSUMER_KEY', '8MGOAAJf4UXQ9kBSgCZf28Rbrn');
define('TWITTER_CONSUMER_SECRET', 'L5HdWIvYn4GXFSOLDJceLAXdPmFR3nIvahQViebWXU6Dm1zJSr');
define('TWITTER_REDIRECT_URL', 'http://localhost/twitterlogin/twitteroauthcallback.php');

Replace all constants with your own database configuration, as well as your Twitter consumer and secret keys.

The TWITTER_REDIRECT_URL should be the exact same as the callback URL you have in your project. In this case it needs to be http://localhost/twitterlogin/twitteroauthcallback.php.

Client-facing Code

Copy and paste the next code snippets to the remaining files in the root directory.

index.php

<?php
session_start();

if(isset($_SESSION['twitter_user_id'])) {
  require 'twitter-api/userinfo.php';
} else {
  header('Location: errorpage.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>

loginform.php

<?php
session_start();
require 'twitter-api/twitterlogin.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 Form</var></h2>
    <p>&nbsp;</p>
    <div class="btn-group">
      <?php echo $twitt_button; ?>
    </div>
  </body>
</html>

logout.php

<?php
// Initialize the session.
session_start();
// Remove user data from session
unset($_SESSION['twitter_user_id']);
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>

Backend/API-facing Code

Within the twitter-api folder, create a file named twitterlogin.php. We’ll begin the code procedure by requiring autoload.php from the twitter API we earlier downloaded and a call to TwitterOAuth.

twitter-api/twitterlogin.php

<?php

require 'twitter/vendor/autoload.php';
require_once 'config.php';

use Abraham\TwitterOAuth\TwitterOAuth;

// Begins
$connectTwitter1 = new TwitterOAuth( TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET );

// Get a request token
$request_token = $connectTwitter1->oauth( 'oauth/request_token', array( 'oauth_callback' => TWITTER_REDIRECT_URL ) );

$_SESSION['oauth_token'] = $request_token['oauth_token'];
$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];

$connectTwitter2 = new TwitterOAuth( TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET, $_SESSION['oauth_token'], $_SESSION['oauth_token_secret'] );
$verify_authentication = $connectTwitter2->url( 'oauth/authenticate', array( 'oauth_token' => $request_token['oauth_token'] ) );

// Create a button for the login action
$twitt_button = '<button><a href="'.htmlspecialchars($verify_authentication).'" id="twitter" name="twitter">Login with Twitter</a></button>';

Code Explanation

Request Token

To obtain a request token, you have to create a first instance of the TwitterOAuth class with the TWITTER_CONSUMER_KEY and the TWITTER_CONSUMER_SECRET as the parameters. Obtain the request token with 'oauth/request_token' as recommended by the updated Log in with Twitter guide on Obtaining a Request Token. The request token, which is first of the three legged authentication, is returned with an oauth_token and an oauth_token_secret values. Assign both values to sessions and use them as parameters to create a second instance of the TwitterOAuth class.

Authentication

The next step is to request for user authentication using the second TwitterOAuth instance and the oauth/authenticate. The goal is to verify the redirect URL and obtain an authentication from the user who is requesting a login access. When the redirect is successful, this request returns an oauth_token and an oauth_verifier, which is then used to make the final request in the twitteroauthcallback.php file that we are about to create.. You can learn more about it in Redirecting the User guide.

Access Token

A final leg of the authentication will take place in the code below;

twitteroauthcallback.php

<?php
require 'twitter/vendor/autoload.php';
require 'config.php';

use Abraham\TwitterOAuth\TwitterOAuth;
session_start();

if ( isset( $_GET['oauth_verifier'] ) && isset( $_GET['oauth_token'] ) && isset( $_SESSION['oauth_token'] ) && $_GET['oauth_token'] == $_SESSION['oauth_token'] ) {
  $connectTwitter3 = new TwitterOAuth( TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET, $_SESSION['oauth_token'], $_SESSION['oauth_token_secret'] );

  $access_token = $connectTwitter3->oauth( 'oauth/access_token', array( 'oauth_verifier' => $_GET['oauth_verifier'] ) );
  $_SESSION['access_twitter'] = $access_token;

  if (isset($_SESSION['access_twitter']) && $_SESSION['access_twitter']) {
    $oauthenticate = $_SESSION['access_twitter']['oauth_token'];
    $oauthenticate_secret = $_SESSION['access_twitter']['oauth_token_secret'];

    // Use the access token session to fetch the oauth_token and oauth_secret_token.
    $verifier = new TwitterOAuth( TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET, $oauthenticate, $oauthenticate_secret );

    $getUser = $verifier->get( 'account/verify_credentials', ['include_email' => 'true'] );
    if (property_exists($getUser, 'error')) {
      $_SESSION = array();

      // If it's desired to kill the session, also delete the session cookie.
      // Note: This will destroy the session, and not just the session data!
      if (ini_get("session.use_cookies")) {
        $params = session_get_cookie_params();
        setcookie(session_name(), '', time() - 42000,
          $params["path"], $params["domain"],
          $params["secure"], $params["httponly"]
        );
      }
      // Finally, destroy the session.
      session_destroy();
      header('Location: errorpage.php');
      exit();
    } else {
      $getUser = $verifier->get( 'account/verify_credentials', ['include_email' => 'true']);
      $twtID = mysqli_real_escape_string($getUser->user_id);
      $twtname = mysqli_real_scape_string($getUser->name);
      $twtemail = mysqli_real_scape_string($getUser->email);
      $twtimage = mysqli_real_scape_string($getUser->profile_image_url);
      $twtUserQuery = "SELECT `twitter_id` FROM  `twt_users` WHERE twitter_id = '".$twtID."'";
      $result = mysqli_query($conn, $twtUserQuery);

      if (mysqli_num_rows($result) > 0) {
        $updateUser = "UPDATE `twt_users` SET name = '" . $twtname ."' AND email = '" . $twtemail ."' AND profile_image = '" . $twtimage . "'";
        $updated = mysqli_query($conn, $updateUser);
      } else {
        // Add user to the database
        $newUser = "INSERT INTO `twt_users` (`twitter_id`, `name`, `email`, `profile_image`) VALUES('". $this->google_id ."','" . $this->name. "','" . $this->email . "','" . $this->profile_image."')";
        $newUserResult = mysqli_query($newUser);
      }

      $row = mysqli_fetch_assoc($result);
      if ($row) {
        extract($row);
        $_SESSION['twitter_user_id'] = $twitter_id;
        header('location: index.php');
        exit();
      }
    }
  }
}

If the values of oauth_token and oauth_verifier, along with the other tokens are true, then create a third instance of the TwitterOAuth class and request for an access token using 'oauth/access_token'. You can learn more about Converting the Request token to an Access token. Save the access token in a session and use it to make yet another request that will verify and fetch user credentials. Save the credentials to the database.

twitter-api/userinfo.php

<?php
require_once 'dbconfig.php';

$twt_id = $_SESSION['twitter_user_id'];
$user_data = "SELECT * FROM `twt_users` WHERE `twitter_id` = '$twt_id'";
$querydb = mysqli_query($conn, $user_data);
if(mysqli_num_rows($result) > 0) {
  $result_object = mysqli_fetch_assoc($querydb);
}
else {
  header('Location: logout.php');
  exit();
}

The last code snippets queries the database for the user’s information and saves it in $result_object as an associative array.

Conclusion

The Twitter login unlike the previous systems featured in the series is achieved through a procedural execution. I opted out of OOP in the code implementation as every other class tends to interfere with the TwitterOAuth class. It’s something you should probably look into for yourself.