Search code examples
google-apigoogle-oauthgoogle-signingoogle-api-php-clientgoogle-api-client

Google sign-in for websites: read user's phone number


I want to obtain users' phone numbers via Google sign-in on my website. In JavaScript for the "sign in with Google" button, I'm including scope 'https://www.googleapis.com/auth/user.phonenumbers.read' for permission to read the user's phone number. Maybe instead of this scope, I need to use 'https://www.googleapis.com/auth/contacts.readonly'. In any case, how do I obtain a signed-in user's phone number in PHP or JavaScript? When a user clicks on the sign-in button then because of the scope Google does ask permission to share a phone number. In Google API Console -> Edit app registration -> Scopes, I've included this phone number scope. Also, I've enabled People API in the Google project. I've installed

composer require google/apiclient

From the front end i'm receiving id-token for the signed-in user. My PHP is:

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

$id_token = $_POST['idtoken'];

$client = new Google_Client(['client_id' => '349001386451-bpovja3t7soabdu3cbhnig12fqlr20o0.apps.googleusercontent.com']);
$payload = $client->verifyIdToken($id_token);
if ($payload) {
  $userid = $payload['sub'];
  echo "Userid: $userid";
} else {
  echo "Invalid ID token";
}

( The above code has been edited from https://developers.google.com/identity/sign-in/web/backend-auth )
I'm a newbie to this. I've got my client-id, client-secret and user's id-token. I'm able to show the userid in the above code, how to display the phone number?


Edit: I downloaded my client_secret.json and tried another method:

index.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google\Client();
$client->setAuthConfig('client_secret.json');

$client->setScopes(array('https://www.googleapis.com/auth/user.phonenumbers.read', 'https://www.googleapis.com/auth/contacts.readonly', 'profile'));

if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
  $client->setAccessToken($_SESSION['access_token']);
  $service = new Google_Service_PeopleService( $client );
  $optParams = ['personFields' => 'phoneNumbers'];
  $profile = $service->people->get( 'people/me', $optParams );
  var_export($profile);
  var_export( $profile->getPhoneNumbers() );
} else {
  $redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . '/testing/oauth2callback.php';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

--

oauth2callback.php

<?php
require_once __DIR__.'/vendor/autoload.php';

session_start();

$client = new Google\Client();
$client->setAuthConfigFile('client_secret.json');
$client->setRedirectUri('https://' . $_SERVER['HTTP_HOST'] . '/testing/oauth2callback.php');
$client->addScope(Google_Service_PeopleService::USER_PHONENUMBERS_READ);

if (! isset($_GET['code'])) {
  $auth_url = $client->createAuthUrl();
  header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
  $client->authenticate($_GET['code']);
  $_SESSION['access_token'] = $client->getAccessToken();
  $redirect_uri = 'https://' . $_SERVER['HTTP_HOST'] . '/testing/';
  header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}

But when I'm running index.php it's giving error:

"error": { "code": 403, "message": "The caller does not have permission to request "people/me". Request requires one of the following scopes: [profile]."

But I do have included the profile scope in index.php


Solution

  • I'm successfully getting phone number using a new 3rd method as given here:
    https://developers.google.com/people/api/rest/v1/people/get?apix=true&apix_params=%7B%22resourceName%22%3A%22people%2Fme%22%2C%22personFields%22%3A%22phoneNumbers%22%7D

    I copied the JavaScript code given in this link, removed all scopes except one, replaced YOUR_API_KEY and YOUR_CLIENT_ID, ran it on my server, in Firefox and it worked!

    <script src="https://apis.google.com/js/api.js"></script>
    <script>
      /**
       * Sample JavaScript code for people.people.get
       * See instructions for running APIs Explorer code samples locally:
       * https://developers.google.com/explorer-help/guides/code_samples#javascript
       */
    
      function authenticate() {
        return gapi.auth2.getAuthInstance()
            .signIn({scope: "https://www.googleapis.com/auth/user.phonenumbers.read"})
            .then(function() { console.log("Sign-in successful"); },
                  function(err) { console.error("Error signing in", err); });
      }
      function loadClient() {
        gapi.client.setApiKey("YOUR_API_KEY");
        return gapi.client.load("https://people.googleapis.com/$discovery/rest?version=v1")
            .then(function() { console.log("GAPI client loaded for API"); },
                  function(err) { console.error("Error loading GAPI client for API", err); });
      }
      // Make sure the client is loaded and sign-in is complete before calling this method.
      function execute() {
        return gapi.client.people.people.get({
          "resourceName": "people/me",
          "personFields": "phoneNumbers"
        })
            .then(function(response) {
                    // Handle the results here (response.result has the parsed body).
                    console.log("Response", response);
                  },
                  function(err) { console.error("Execute error", err); });
      }
      gapi.load("client:auth2", function() {
        gapi.auth2.init({client_id: "YOUR_CLIENT_ID"});
      });
    </script>
    <button onclick="authenticate().then(loadClient)">authorize and load</button>
    <button onclick="execute()">execute</button>
    

    But it only reads the phone number(s) added in Google account's "About me": https://myaccount.google.com/profile
    And not the phone number of Google account which is used for password reset. I actually want this number but don't know whether possible.