Signing up to new web platforms with existing social media accounts have become more preferable to users than the traditional email registration system. Social media login is among the most desired and requested features when it comes to most web and mobile applications. In this article, we will demonstrate the web implementation of the Google login system.

How to get the Google OAuth 2.0 Client Secret & the Client ID

Log in to the Google Cloud Platform with your google account and create a new project. Provide a name for the project and CREATE.

new-project

On the dashboard, click on credentials, and then click on Configure Consent Screen button.

credentials

Select External and CREATE.

oauth-consent-screen

Complete all relevant fields in the App Information form and click on SAVE AND CONTINUE three times over and you are done. Go to Credentials once again and click on +CREATE CREDENTIALS and select OAuth client ID.

create-credentials

On the Create OAuth client ID page, choose Web application.

create-oauth-client-id

Provide an OAuth 2.0 client name, and an Authorized Redirect URI. Then proceed to CREATE. Note that http://localhost/social_login/index.php is a valid URI if you are trying this out on localhost. You should also make sure to provide the very same ‘Redirect URI’ in your configuration code.

oauth-client

At this point, you now have a Client ID and a Client Secret.

Prepare the 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 google-login-client.

In order to download the Google client API needed for our user authentication, navigate into google-login-client from your terminal and run the command below;

$ composer require google/apiclient:^2.0

MySQL Database

Be it MAMP, WAMPServer, XAMPP or anything else you may be using, make sure your local server is started and running. Use your phpMyAdmin client to create a new database named social_systems. In your MySQL console, run the following SQL commands;

/** MySQL console*/
USE social_systems;
CREATE TABLE google_users (
  id int(11) NOT NULL AUTO_INCREMENT,
  google_id varchar(255) NOT NULL,
  name varchar(150) NOT NULL,
  email varchar(150) NOT NULL,
  profile_image text NOT NULL,
  primary key (id),
  unique key google_id (google_id)
);

Code Implementation

Copy the given code into their respective files as indicated in the file path associated with each file.

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('GOOGLE_CLIENT_ID', '[YOUR ID]');
define('GOOGLE_CLIENT_SECRET', '[YOUR SECRET]');
define('GOOGLE_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;
  }
}

We’re havving here all our configuration data provided in config-files/config.php, and the database connection defined in config-files/Database.php. Lets create a User class that will handle user attributes as well as a method for the user to login to your application with google data.

users/User.php

<?php
class User {
  // Database related data
  private $cxn;
  private $google_account_table = 'google_users';

  // Google User Properties
  public $id;
  public $name;
  public $email;
  public $profile_image;
  public $google_id;

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

  // Google Login
  public function google_login($ggldata = array()) {
    if(!empty($ggldata)) {
      //Ensure the user entry does not already exist.
      $this->google_id = $this->cxn->real_escape_string($ggldata['id']);
      $this->name = $this->cxn->real_escape_string($ggldata['name']);
      $this->email = $this->cxn->real_escape_string($ggldata['email']);
      $this->profile_image = $this->cxn->real_escape_string($ggldata['picture']);
      $gglUser = "SELECT `google_id` FROM " . $this->google_account_table . " WHERE google_id = '".$this->google_id."'";
      $gglUserResult = $this->cxn->query($gglUser);

      if($gglUserResult->num_rows > 0) {
        // return $execute_get_user->fetch_assoc();
        $gglUserUpdate = "UPDATE " . $this->google_account_table . " SET name = '" . $this->name ."' AND email = '" . $this->email ."' AND profile_image = '" . $this->profile_image . "'";
        $updatedGglUserResult = $this->cxn->query($gglUserUpdate);
      } else {
        // Add user to the database
        $this->google_id = $this->cxn->real_escape_string($ggldata['id']);
        $this->name = $this->cxn->real_escape_string($ggldata['name']);
        $this->email = $this->cxn->real_escape_string($ggldata['email']);
        $this->profile_image = $this->cxn->real_escape_string($ggldata['picture']);

        $newGglUser = "INSERT INTO ". $this->google_account_table . " (`google_id`, `name`, `email`, `profile_image`) VALUES('". $this->google_id ."','" . $this->name. "','" . $this->email . "','" . $this->profile_image."')";
        $newGglUserResult = $this->cxn->query($newGglUser);
      }
    } else {
      header('Location: errorpage.php');
      exit();
    }
    return $gglUserResult->fetch_assoc();
  }
}

In the User class, we have the google_login function receive an array of google data as a parameter. It updates the database if the user exists, or inserts into the database where there’s no such user.

google-login-client/googlelogin.php

<?php
require_once('vendor/autoload.php');

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

// Instantiate a Database object
$database = new Database();
$connection = $database->connect();

// Instantiate a User object
$gUser = new User($connection);

$client = new Google_Client();
$client->setClientId(GOOGLE_CLIENT_ID);
$client->setClientSecret(GOOGLE_CLIENT_SECRET);
$client->setRedirectUri(GOOGLE_REDIRECT_URL);

// Scope of Interest on Google API
$client->addScope('email');
$client->addScope('profile');

if(isset($_GET['code'])){
  $token = $client->fetchAccessTokenWithAuthCode($_GET['code']);

  if(!isset($token['error'])) {
    $client->setAccessToken($token['access_token']);

    // Get profile info from Google API
    $google_oauth = new Google_Service_Oauth2($client);
    $google_account_info = $google_oauth->userinfo->get();

    // Pull google data into the database
    $user_data = array();
    $user_data['id'] = !empty($google_account_info['id']) ? $google_account_info['id'] : '';
    $user_data['name'] = !empty($google_account_info['name']) ? $google_account_info['name'] : '';
    $user_data['email'] = !empty($google_account_info['id']) ? $google_account_info['email'] : '';
    $user_data['picture'] = !empty($google_account_info['id']) ? $google_account_info['picture'] : '';

    $result = $gUser->google_login($user_data);
    if($result) {
        extract($result);
        $_SESSION['google_user_id'] = $google_id;
        header('location: index.php');
        exit();
    }
  } else {
    header('Location: errorpage.php');
    exit();
  }
} else {
  $googleAuthUrl = $client->createAuthUrl();
  // Render Google login button
  $googleButton = '<button><a href="'.htmlspecialchars($googleAuthUrl).'" id="google" name"google">Login with Google</a></button>';
}

Create a Google client instance of the Google API class in a variable $client and use it to call the Google API using the methods setClientId(), setclientSecret(), setClientRedirectUri() and addScope(). On a condition that the client receives a “code” from a GET request, it sets up an access token that allows the client to obtain user profile information from the Google API.

On the other hand when there is no “code” received from the GET request, the client uses the createAuthUrl() method to obtain a URL with a code via a GET request from the client to the Google API.

users/googledata.php

<?php
require_once('users/User.php');
require_once('config-files/Database.php');

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

$ggl_id = $_SESSION['google_user_id'];

$user_data = "SELECT * FROM `ggle_users` WHERE `google_id` = '$ggl_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();
}

In the users/googledata.php file, a session created with the user’s google ID is used to query the database for the user’s saved data. The result of that query goes into index.php.

loginform.php

<?php
session_start();
require_once('google-login-client/googlelogin.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;}

      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 $googleButton; ?>
      </div>
  </body>
</html>

index.php

<?php
session_start();
if(isset($_SESSION['google_user_id'])) {
  require_once('users/googledata.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['google_user_id']);
// Finally, destroy the session.
session_destroy();
header("Location: loginform.php");
exit();
?>

It may not be a neccesity, but it’s good to add this simple error page to your root directory to help you determine when something goes wrong.

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

Google login implementation is just about that simple. Windows users may encounter a little problem with the user authentication asking for a certificate of authentication. One way to solve this problem is by downloading the cacert.pem file from here. Copy the downloaded file to a path of your choice. Then at the end of your php.ini file, add curl.cainfo=c:/path/to/cacert.pem and openssl.cafile="C:/path/to/cacert.pem" and save the changes.