Search code examples
phpmysqlgoogle-one-tap

How to integrate Google one tap sign in?


I want to integrate Google Onetap Sign in with my PHP & MySQL website. The code I have is, this old login using google sign in button is working but i dont know about google one tap sign in.

    <?php //config.php

//Include Google Client Library for PHP autoload file
require_once 'vendor/autoload.php';

//Make object of Google API Client for call Google API
$google_client = new Google_Client();

//Set the OAuth 2.0 Client ID
$google_client->setClientId('xxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com');

//Set the OAuth 2.0 Client Secret key
$google_client->setClientSecret('xxxxxxxxxxxxxxxxxxxx');

//Set the OAuth 2.0 Redirect URI
$google_client->setRedirectUri('http://localhost/tutorial/php-login-using-google-demo/index.php');

//
$google_client->addScope('email');

$google_client->addScope('profile');

//start session on web page
session_start();

?>

Solution

  • Looks good so far, though I would recommend against sharing your clientID and ClientSecret on a public forum.

    Google provide instructions for integrating their sign-in service. I recommend following those instructions. This will require the following files:

    1. A login page which contains the google sign-in button. You could conceivably add this to any of your existing pages. The relevant code is:
    <div class="g-signin2" data-longtitle="true" data-onsuccess="onSignIn"></div>
    
    1. A javascript file which contains the onSignIn function and a signOut function if you want one. This file handles the redirect to a successful logged in page and also passes the attributes you want to collect from the user's Google account. I'm using XMLHttpRequest, but you could use POST if you wish. This page contains the page that the user will be directed to upon successful login, set in xhr.onreadystatechange = function() {}:
    function onSignIn(googleUser) {
      var profile = googleUser.getBasicProfile();
        var id_token = googleUser.getAuthResponse().id_token;
    //    console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
        var xhr = new XMLHttpRequest();
        xhr.open('POST', 'includes/oauth.php');
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xhr.onreadystatechange = function() {
            window.location = "../loggedin.php"; //Redirect to loggedin page on completion of oauth.php. Determine if new user or existing user and process accordingly
        }
        xhr.send('idtoken=' + id_token + '&googleId=' + profile.getId() + '&name=' + profile.getName() + '&imageURL=' + profile.getImageUrl() + '&email=' + profile.getEmail());
    }
    
    function signOut() {
        gapi.load('auth2', function() {
            gapi.auth2.init().then(function(){
                var auth2 = gapi.auth2.getAuthInstance();
                auth2.signOut().then(function () {
                    document.location.href = 'includes/logout.php';
                });
            });
        });
    }
    
    1. A file to handle the authentication (referred to as includes/oauth.php in my javascript file above). Note the settings for $leeway - this caused me a lot of grief figuring out that the clock on my server was slower than the Google auth server's clock!):
    require_once '../vendor/autoload.php';
    $jwt = new \Firebase\JWT\JWT; //Allow for discrepancies between server and auth times
    $jwt::$leeway = 60;
    
    $CLIENT_ID = "ENTER_YOUR_CLIENT_ID_HERE";
    $client = new Google_Client(['client_id' => $CLIENT_ID]);  // Specify the CLIENT_ID of the app that accesses the backend
    $client->setRedirectUri("http://localhost/includes/oauth.php");
    $client->addScope("email");
    $client->addScope("profile");
    
    if (isset($_POST['idtoken'])){
        $id_token = $_POST['idtoken'];
        $attempt = 0;
        do {
            try {
                $payload = $client->verifyIdToken($id_token);
                $retry = false;
            } catch (Firebase\JWT\BeforeValidException $e) {
                error_log("JWT server time mismatch. Retry attempt: " . strval($attempt) . "Error: " . $e, 0);
                $attempt++;
                $retry = $attempt < 3;
            }
        } while ($retry);
    
        if ($payload) {
          $userid = $payload['sub'];
          ...
          YOUR VALIDATION, SESSION SETTING, ETC. CODE HERE
          ...
        } else {
          // Invalid ID token
            print("Invalid ID token");
        }
    } else {  //Attempt to access this page directly, redirect to Google login page
        $auth_url = $client->createAuthUrl();
        header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
    }
    
    
    1. The page that will displayed upon successful login. I used an interstitial page here because the authenticated user could be new to my site and need to create a profile, or could be an existing user and want to go about their activities. I look to verify whether a SESSION has been started and whether this includes a successful authentication.