Categories
Code

Google OAuth 2.0 Service account with PHP and Google APIs

This sample code uses Google Service Accounts with PHP to get a list of users in a Google Apps Domain using the Admin Directory API.

To get started, install the Google API PHP library, create a Google Service account with domain-wide delegation and save the private JSON file in the same directory as your PHP application.

useApplicationDefaultCredentials(); 
  $client->setApplicationName(APPLICATION_NAME);
  $client->setScopes(SCOPES); 
  $client->setAccessType("offline");
  $client->setSubject($user);

  $service = new Google_Service_Directory($client); 

  $optParams = array( 
    'domain' => 'ctrlq.org', 
    'maxResults' => 10, 
    'orderBy' => 'email'
  ); 

  $results = $service->users->listUsers($optParams); 

  print_r($results);

?>
Categories
Code

How to Create Google Service Accounts

This step by step tutorial will walk you through the steps to create a Google service account using the Google developer console. We’ll also see how to enable Google APIs that our application will access via the service account credentials.

1. Go to console.developers.google.com and create a new project. Let’s call this Service Accounts Tutorial.

create-service-account.png

2. Go to the Library section and enable a couple of Google APIs and service that you will use in the project.

2017-01-17_12-05-24.096.png

3. Enable the Admin SDK. This will allow the Google Apps domain to manage the users in the domain.

2017-01-17_12-07-14.140.png

4. Go to the manu, choose IAM & Admin, Service Accounts and create a new service account.

Set the Role as Service Account Actor, choose JSON for the private key, enable G Suite Domain-wide delegation. This is essential since we would like the application to access the data of all user’s in the G Suite domain without manual authorization on their part.

service-account-domain-wide-delegation.png

The JSON file that contains the client credential will download to your computer. Store it in a safe location because you will not be able to download it again.

The service account has been successfully created. The JSON fill will the Private key and the Client Email that will use in our application. The file will also have the Client ID that will need to whitelist this application in the Google Apps admin console.

google-apps-service-account-private-key.png

In the next chapter, we’ll see how the G Suite domain administrator can setup the OAuth2 application inside admin console for domain wide delegation.

Categories
Code

Service Accounts and Google APIs – Introduction

When a user connects to an application that uses OAuth 2 authentication, they are presented with a consent screen that describes what information about their account will be shared with the application and it may also includes a list of various Google APIs that the application has requested access to.

Google’s authorization server provides an access token to the application that they can pass to Google with all future requests to authenticate the request.

However in some cases, you may want to build a server-side application that connects directly to Google services without the involvement of the end-user. That’s where Service Accounts come into the picture.

Service Accounts are pre-authorized meaning the user has already granted access to a service account to access Google services on their behalf. The application then uses the service account credentials to connects to Google APIs removing the user from the equation.

The service account acts sort of virtual user and they have an email address so you can share your Google Calendar, Google Drive folders and other resources with a service account. If you are building a web app that uses Google Drive APIs for converting documents from one format to another, service accounts may be an option as the user would not be required to grant access to their own Google Drive for converting files.

Service Accounts with OAuth also support user impersonation and this is particularly useful for Google Apps admins that can build apps to access data of any user in the Google Apps domain. For instance, the Google Apps admin can use service accounts to audit shared files of all users in the organization.

In the next section, we’ll look at the step to create a service account inside the Google Developer console.

Categories
Code

Configure OAuth2 Service Accounts for Domain-wide Delegation

The tutorial describes how the Google Apps domain of a G Suite domain can configure an OAuth2 Service account application for domain wide delegation. That is, the service account user can act on behalf of any other user of the Google Apps domain.

1. Go to admin.google.com and sign in to the G Suite administrative console.

2. Click the Security icon, choose API reference and check the option Enable API access. This will allow the admin programatic access to various G Suite Administrative APIs.

api-access-admin-console.png

3. On the Security Page, click Show More and then choose Advanced Settings. In the Advanced Setting section, click Manage API access. The domain admins can use this section to control access to user data by applications that use OAuth protocol.

2017-01-17_12-36-51.299.png

4. You can now authorize whitelisted application to access the data of the domain users without them having to individually give consent or their passwords. Also, you need to specify a list of OAuth 2.0 API scopes (comma separated) that the authorized API client is allowed access to on user’s behalf.

You can get the Client ID from the JSON file while the API scopes are the all the APIs that we have enabled while creating the Google Service Account.

api-client-access.png

For instance, if your application needs access to user’s Gmail, Google Drive and Admin SDK, the API scopes would be:

https://www.googleapis.com/auth/admin.directory.user.readonly, https://mail.google.com, https://www.googleapis.com/auth/drive

The service account is now ready and the application is authorized in the Google Apps admin console. In the next step, we’ll look a building an OAuth2 application that uses Google Service Accounts with Google Apps Script.

Categories
Code

Tutorial: Create Application with Google APIs and OAuth 2

Now that you understand the basics of Google OAuth 2, let’s build a simple application that uses OAuth 2.0 for connecting to Google API’s on user’s behalf.

1. Go to console.developers.google.com and create a new project.

2017-01-16_22-23-56.311.png

2. Give your project a name.2017-01-16_22-25-24.046.png

3. Go to Library, search for the Google APIs that you wish to use in your application and enable them one by one.

enable-gmail-api.png

4. Go to Credentials -> Create Credentials -> Oauth Client Id. We’ll discuss service accounts in a later chapter.

oauth-client-id.png

5. On the credentials screen, choose “Web Application” for the “Application Type” and http://localhost:8080 under Authorized redirect URIs and Authorized JavaScript origins.

If you have a live web server running PHP, you can put the site address for the redirect URI but for this application, we will only use a local server running on port 8080. You only need to specify the port if your web service is running on a port than 80 (standard).

google-oauth-credentials.png

Google will show you the Client ID and Client Secret on the next screen. Dismiss the window and instead download the JSON file containing your OAuth client credentials. Move this JSON file in the root directory of your PHP application.

client-secret-json.png

In the next section, we’ll look at the actual PHP example that will connect our application to the user’s Gmail account via OAuth.

Categories
Code

An Introduction to OAuth 2 and Google APIs

google-apps-gsuite.png

OAuth 2, in simple English, is a simple protocol that makes it easy for third-party applications to access a user’s account without the user having to give out their username and password to the application. Let me explain with an example.

The Save Emails addon downloads email messages from a user’s Gmail account to their Google Drive. The addon is the third-party application in this case and it can use OAuth 2.0 to obtain permission from the user to access their Gmail and Google Drive via standard Google APIs. The user can revoke access to the addon anytime. Also, if the user changes the password of their Google account later, the OAuth 2 connection will continue to work.

OAuth 2.0 Flow and Google APIs

The OAuth 2.0 flow is something like this.

  1. You create a new project in the Google Console for your application and generate the client ID and client secret. These keys are known both to your application and Google.
  2. Enable the various Google APIs that your application would use to obtain data from the user’s account. For instance, if you are the admin of a Google Apps domain, you may want to activate the Admin Directory SDK to get a list of all users in the domain.
  3. The application then redirects the browser to a  URL on the Google server. Here the user needs to give consent on whether the application should be granted access to their data on not.
  4. If the user approves, the Google Authorization Server redirects the user back to your application with a single-use authorization code that can be exchanged for a short-lived access token and a refresh token.
  5. Store the tokens in Google Cloud Storage, Firebase, MySQL database or even the local filesystem for command line applications.
  6. All future requests to the Google APIs should include this access token. The access token expires after some time so your application can use the refresh token to obtain a new access token. The refresh tokens do not expire.

In the next section, we’ll build a simple web application that uses OAuth 2.0 with Gmail API and Google PHP library to generate a list of all labels in the user’s mailbox.

Build OAuth 2 Application with Google APIs

Categories
Code

Connect to Google API with PHP and OAuth2 – Sample Code

This sample application describes how your PHP application can connect to the user’s Gmail account using the Google PHP client library and OAuth2. You’ll need to create the application inside Google Console.

The Client ID and secret are stored in a separate JSON while the access token and refresh token are also stored in the local file system.

setApplicationName("ctrlq.org Application");
  $client->setAuthConfig($KEY_LOCATION);
  
  // Incremental authorization
  $client->setIncludeGrantedScopes(true);
  
  // Allow access to Google API when the user is not present. 
  $client->setAccessType('offline');
  $client->setRedirectUri($REDIRECT_URI);
  $client->setScopes($SCOPES);
  
  if (isset($_GET['code']) && !empty($_GET['code'])) {
      try {
          // Exchange the one-time authorization code for an access token
          $accessToken = $client->fetchAccessTokenWithAuthCode($_GET['code']);
          
          // Save the access token and refresh token in local filesystem
          file_put_contents($TOKEN_FILE, json_encode($accessToken));
          
          $_SESSION['accessToken'] = $accessToken;
          header('Location: ' . filter_var($REDIRECT_URI, FILTER_SANITIZE_URL));
          exit();
      }
      catch (\Google_Service_Exception $e) {
          print_r($e);
      }
  }
  
  if (!isset($_SESSION['accessToken'])) {
      
      $token = @file_get_contents($TOKEN_FILE);
      
      if ($token == null) {
          
          // Generate a URL to request access from Google's OAuth 2.0 server:
          $authUrl = $client->createAuthUrl();
          
          // Redirect the user to Google's OAuth server
          header('Location: ' . filter_var($authUrl, FILTER_SANITIZE_URL));
          exit();
          
      } else {
          
          $_SESSION['accessToken'] = json_decode($token, true);
          
      }
  }
  
  $client->setAccessToken($_SESSION['accessToken']);
  
  /* Refresh token when expired */
  if ($client->isAccessTokenExpired()) {
      // the new access token comes with a refresh token as well
      $client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
      file_put_contents($TOKEN_FILE, json_encode($client->getAccessToken()));
  }
  
  $gmail = new Google_Service_Gmail($client);
  
  $opt_param               = array();
  $opt_param['maxResults'] = 10;
  
  $threads = $gmail->users_threads->listUsersThreads("amit@labnol.org", $opt_param);
  
  foreach ($threads as $thread) {
      print $thread->getId() . " - " . $thread->getSnippet() . '
'; } ?>
Categories
Code

Google URL Shortener with Google Scripts

You can use Google Apps Script with the Google URL Shortener API to convert any long URL into a short one served through the goo.gl domain. Make sure you replace key with your own key from the Google Console dashboard. You can also bit.ly to shorten URLs.


function shortenURL(longUrl) {
  
  var key = "YOUR_KEY";
  var serviceUrl="https://www.googleapis.com/urlshortener/v1/url?key="+key;
  
  var options={
    muteHttpExceptions:true,
    method:"post",
    contentType: "application/json",
    payload : JSON.stringify({'longUrl': longUrl })
  };
  
  var response=UrlFetchApp.fetch(serviceUrl, options);
  
  if(response.getResponseCode() == 200) {
    var content = JSON.parse(response.getContentText());
    if ( (content != null) && (content["id"] != null) )
      return content["id"];
  }
  
  return longUrl;
}

The other easier alternative for creating short URLs with the Google URL shortener API doesn’t require you to create a key as it passes the OAuth 2.0 access token for the current user in the header.



function shortenUrl(longURL){

  var url = "https://www.googleapis.com/urlshortener/v1/url"
  
  var payload = {"longUrl":longURL};
  
  var parameters = { 
          method : 'post',
          headers : {'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()},
          payload:JSON.stringify(payload),
          contentType:'application/json',                    
          muteHttpExceptions:true
  };
        
  var response = UrlFetchApp.fetch(url, parameters);
  
  Logger.log(response);
  
}
Categories
Code

Save Google PageSpeed Score in Google Sheet

The Google PageSpeed score helps you understand how fast your website will load on a desktop or mobile phone. It has other critical information like the file size, number of external resources requested and the number of hosts your site needs to connect. You can log all this insights data in a Google Spreadsheet automatically using a time-based trigger and visualize your site’s performance over time.


/* Source: http://qiita.com/takoratta/items/9b8d33970d07125e4f96 */
function pageSpeed(url) {
  
  url = url || 'http://ctrlq.org/';
  
  var APIkey   = 'XYZ';     // Get the API key from Google Dev Console
  var strategy = 'desktop'; // 'desktop' or 'mobile'
  
  var api = 'https://www.googleapis.com/pagespeedonline/v1/runPagespeed?url=' 
                + url + '&key=' + APIkey +  '&strategy=' + strategy;
  
  var response = UrlFetchApp.fetch(api, {muteHttpExceptions: true });
  
  var parsedResult = JSON.parse(response.getContentText());
  var pageSpeedResults = {};
  
  pageSpeedResults['score'] = parsedResult.score;
  
  var pageStats = ['numberResources', 'numberHosts', 'totalRequestBytes', 
                   'numberStaticResources', 'htmlResponseBytes', 'cssResponseBytes', 
                   'imageResponseBytes', 'javascriptResponseBytes', 
                   'otherResponseBytes', 'flashResponseBytes','textResponseBytes', 
                   'numberJsResources', 'numberCssResources'];
  
  for (var i=0; i < pageStats.length; i++) {
    pageSpeedResults[pageStats[i]] = parsedResult.pageStats[pageStats[i]];
  }
  
  return(pageSpeedResults);

}
Categories
Code

RSS Feed for Google+

This PHP script will generate an RSS Feed for Google Plus users. You can need to replace the PlusID with your own Profile ID and the Google API key that can be obtained from code.google.com.

Google+ allows you to retrieve content from the network but the API doesn’t allow you post content on Google Plus. Code courtesy @SplitBrain/Github.

\n";
echo "\n";
echo "\n";
echo " ".htmlspecialchars($gplus->title)."\n";
echo " http://plus.google.com/$googlePlusID\n";
echo " \n";
echo " ".$gplus->updated."\n";
echo " ".$gplus->updated."\n";
foreach($gplus->items as $item) {
echo " \n";
echo " ".htmlspecialchars($item->title)."\n";
echo " ".htmlspecialchars($item->url)."\n";
echo " ".htmlspecialchars($item->id)."\n";
echo " ".$item->updated."\n";

// we might add a source quote from attachments
$desc = $item->object->content;

if(isset($item->object->attachments)) foreach($item->object->attachments as $attach){
if($attach->objectType == 'article'){
$desc .= '

';
$desc .= ''.$attach->displayName.'

';
$desc .= $attach->content;
$desc .= '

';
}elseif($attach->objectType == 'photo'){
echo " image->url)."\" type=\"".$attach->image->type."\" />\n";
}// FIXME what other attachement type need to be supported?
}

echo " ".htmlspecialchars($desc)."\n";

if($item->geocode){
list($lat,$lon) = explode(" ",$item->geocode);
echo " $lat\n";
echo " $lon\n";
}

echo " \n";
}
echo "\n";
echo "\n";

Categories
Code

Google Handwriting IME API Request

When you write on the Google homepage using handwriting mode, the drawn path is sent as a POST request to Google Input Tools IME API as an array of X,Y points. Following is a sample payload request sent to the Google IME API.

 "method": "POST",
 "url": "https://www.google.com/inputtools/request?ime=handwriting",
 "postData": { "text": "{
   "device":"Chrome/19.0.1084.46 Safari/536.5",
   "options":"enable_pre_space",
   "requests":[{"writing_guide":{
     "writing_area_width":1920,
     "writing_area_height":617},
    "ink":[[[582,582,582,581,581,580],
            [273,274,275,275,276,276],
            [0,529,537,554,569,1009]]],
     "language":"en"}]}"} 

And here’s a snippet of deobfuscated JavaScript code that traces and sends your handwriting to Google IME API.

_.Qx = function () {
    if (!(0, _.Dx)()) {
        var a = (0, _.rx)(_.Mx, _.Cx.slice(0)),
            b = {
                writing_guide: {
                    writing_area_width: _.yx.width,
                    writing_area_height: _.yx.height
                },
                ink: (0, _.tc)(_.Cx, function (a) {
                    return [(0, _.tc)(a, function (a) {
                        return a.x
                    }), (0, _.tc)(a, function (a) {
                        return a.y
                    }), (0, _.tc)(a, function (a) {
                        return a.t
                    })]
                })
            }, c = (0, _.Rx)();
        c && 0 < c.length && (b.pre_context = c);
        c = window.google.kHL || "en";
        c = c.replace("-", "_");
        b.language = c;
        var b = window.JSON.stringify({
            device: window.navigator.userAgent,
            options: "enable_pre_space",
            requests: [b]
        }),
            d = new _.jx;
        _.kx.push(d);
        c && (0, _.cn)(d, "complete", c);
        (0, _.cn)(d, "ready", (0, _.Ya)(_.yda, d));
        d.lK = window.Math.max(0, 6E3);
        d.send("/inputtools/request?ime=handwriting&app=gws&cs=1",
         "POST", b, { "Content-Type": "application/json" })
    }
    _.Ux.clearRect(0, 0, _.yx.width, _.yx.height);
    _.Bx = _.o;
    _.Cx = [];
    (0, _.Vx)()
};

_.Gx = function (a) {
    var b = (new window.Date).getTime() - _.Jx;
    if (!a.touches) {
        var c = a.pageX - window.pageXOffset,
            a = a.pageY - window.pageYOffset;
        return {
            x: c,
            y: a,
            t: b
        }
    }
    c = a.touches[0].pageX - window.pageXOffset;
    a = a.touches[0].pageY - window.pageYOffset;
    return {
        x: c,
        y: a,
        t: b
    }
};

_.zx = function () {
    _.Ux.clearRect(0, 0, _.yx.width, _.yx.height);
    _.Ux.save();
    _.Ux.lineWidth = 6;
    _.Ux.fillStyle = "#4d90fe";
    _.Ux.strokeStyle = "#4d90fe";
    _.Ux.lineCap = "round";
    _.Ux.lineJoin = "round";
    _.Ux.shadowColor = "rgba(0,0,0,0.3)";
    _.Ux.shadowBlur = 3;
    _.Ux.shadowOffsetY = 2;
    for (var a = 0; a < _.Cx.length; a++)(0, _.Wx)(_.Ux, _.Cx[a]);
    _.Ux.restore()
};
Categories
Code

Parsing RSS Feeds with Google Feed API

The RSS Search Engine and the Social Sharing Analytics tool use the Google Feed API to fetch and parse RSS Feeds.

Here’s how Google Feed API can be used to fetch any RSS Feeds – it can load a maximum of 20 entries per feed.


// Load the Google JavaScript API
<script type="text/javascript" src="http://www.google.com/jsapi"></script>

<script type="text/javascript">

// Load the Google Feeds API
google.load("feeds", "1");

// Parse the query parameters in the REQUEST URL
function qs(search_for) {
    var query = window.location.search.substring(1);
    var parms = query.split('&');
    for (var i = 0; i < parms.length; i++) {
        var pos = parms[i].indexOf('=');
        if (pos > 0 && search_for == parms[i].substring(0, pos)) {
            return parms[i].substring(pos + 1);
        }
    }
    return "http://feeds.labnol.org/labnol";
}

// The RSS feed is in the "q" variable of the Query String
function initialize() {

    var rss = qs("q") 
    var feed = new google.feeds.Feed(rss);

    // Maximum number of allowed entries is 20
    feed.setNumEntries(20);

    feed.load(function (result) {
        if (!result.error) {
            for (var i = 0; i < result.feed.entries.length; i++) {
              console.log ("Title: " + entry.title);
              console.log ("URL: "   + entry.link);
              console.log ("Date: "  + entry.publishedDate);
              console.log ("HTML: "  + entry.content);
            }
        } else 
              console.log("Google Feed API could not find the RSS Feed"); 
    });
 }
 google.setOnLoadCallback(initialize);
</script>