Google Service Account with PHP 54


[wp_ad_camp_5]

Open Authentication Would you like to connect to a Google API using a service account with PHP?   You have come to the right place, in this tutorial we are going to go though the steps needed to connect to the Google Analytics API with a service account.

Accessing the Google APIs using a service account is quite useful. Some times you just want to access your own data and not data owned by other users. In this instance there is no reason to use OAuth2 and prompt a user to give you access to there information, its your information you already have access. This is why we use a service account. This tutorial uses the Google Analytics API to walk you though the steps of creating a service account and how to then access your GA data with it.

What is a Service Account.

A service account will allow your application to access your Google Analytics data without prompting a user for access.  A service account is essentially Oauth1.  Oauth2 is when a user is prompted to give your application permission to use it.     If you are going to only be access your own data then you should be using a Service Account.   If you want to access data owned by another user then you should be using Oauth2 and looking at a different tutorial.  You can find it here   Google Oauth2 PHP

PHP client library

In this tutorial we will be using the newest version of the Google Client library for PHP it can be found on Github.  The  google-api-php-client  client library is updated regularly whenever anything changes.     You will need to copy the entire src/Google directory to the directory of your application.   I don’t recommend only taking the files that you need unless you really know what you are doing.

Google Developers Console

Before you can access any of the Google APIs you need to first create your application in the Google Developers console.    I have a separate tutorial that goes though the steps of creating an application on the Google Developers console you can find it here.    Google Cloud Console   Once you have completed the basic set up including selecting which API that you want to access. For this tutorial we will be using Google Analytics.     Make sure you have filed in both an Email Address and a product name under the consent screen or it wont work.

Creating Service Account

On the Credentials screen you will see a button that says Create new clientid, click on it.   In the popup window selected the “Service account” radio button.    A file will begin to download you will need this file later.    Copy the Email Address that was created for you it should look something like this:  1046123799103-nk421gjc2v8mlr2qnmmqaak04ntb1dbp@developer.gserviceaccount.com

Granting Access

A service account doesn’t need to prompt a user for access because you have to set it up. Go to the Google Analytics website in the Admin section for the Account you want to retrieve data from. This is very important it must be at the account level add this email address as a new user. just give them read access.
serviceaccount

The Code

Conclusion

Using a service account to access your Google Analytics data can be every useful if you would like to store some of your data on your system for further processing. By using a service account you remove the need to prompt a user to give your application access, as long as the application email has access in the Google Analytics account this script will with no need for user intervention. You can see this in action at Google Analytics Reporting API


About Linda Lawton

My name is Linda Lawton I have more than 20 years experience working as an application developer and a database expert. I have also been working with Google APIs since 2012 and I have been contributing to the Google .Net client library since 2013. In 2013 I became a a Google Developer Experts for Google Analytics.

Leave a Reply to Adnan Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

54 thoughts on “Google Service Account with PHP

  • sarah

    it shows this error every time
    Error refreshing the OAuth2 token, message: ‘{ “error” : “invalid_grant” }
    plz help me out

  • Umesh

    Hi Linda
    I read your post, but this does not work anymore! Returns errors as
    Fatal error: Uncaught exception ‘Google_Auth_Exception’ with message ‘Error refreshing the OAuth2 token, message: ‘{ “error” : “invalid_grant” }” in /Applications/MAMP/htdocs/Google/Google/Auth/OAuth2.php:327 Stack trace: #0 /Applications/MAMP/htdocs/Google/Google/Auth/OAuth2.php(289): Google_Auth_OAuth2->refreshTokenRequest(Array) #1 /Applications/MAMP/htdocs/Google/test.php(26): Google_Auth_OAuth2->refreshTokenWithAssertion(Object(Google_Auth_AssertionCredentials)) #2 {main} thrown in /Applications/MAMP/htdocs/Google/Google/Auth/OAuth2.php on line 327

    I think google does not allow to get results without accessing from the browser.
    Could you please anything?

    Thanks
    Umesh

  • Kenny

    This is brilliant. I have been looking for an answer to get non-permission stats into an admin area for a while now and this works great. I had to modify slightly as I am using an oop MVC framework.

    How would i go about gettin say daily results for last 30 days as well?

    I am running a jquery plugin morrischarts which has the ability to draw nice line charts for sales figures so i could convert an array of daily hits to the chart.

    Many thanks.

      • Kenny

        Many thanks again.

        This is the code i came up with and it produces a me 2 line charts one with sessions vs users and one with page views as well as total results for pageviews, sessions,users and bounce rate. I encode the data and place inside my morris line charts javascript to produce a nice overview dashboard.

        //calulating start date
        $gaenddate = date(‘Y-m-d’,strtotime(‘-1 day’));
        $gastartdate = date(‘Y-m-d’,strtotime(‘-31 days’));

        //Adding Dimensions
        $params = array(
        ‘dimensions’ => ‘ga:userType,ga:date’,
        ‘sort’ => ‘ga:date’
        );

        // requesting the data
        $data[‘ga’] = $service->data_ga->get(“ga:”.$ganumber, $gastartdate, $gaenddate, “ga:sessions,ga:pageViews,ga:users,ga:bounceRate”, $params );

  • Milan

    I have
    Warning: file_get_contents(AIzaSyDZIHgXYxV0qLOwSOc2asYzrD14DFvsbic-privatekey.p12): failed to open stream: No such file or directory in C:\wamp\www\GoogleClientApi\googleapitest.php on line 24

    and
    Fatal error: Uncaught exception ‘Google_Auth_Exception’ with message ‘Unable to parse the p12 file. Is this a .p12 file? Is the password correct? OpenSSL error: ‘ in C:\wamp\www\GoogleClientApi\src\Google\Signer\P12.php on line 51
    error in localhost.

  • Manish Thakur

    I tried executing the code locally, I got this error:

    Fatal error: Uncaught exception ‘Google_Auth_Exception’ with message ‘Unable to load private key’ in /var/www/html/gaoauth/Google/Signer/P12.php:70 Stack trace: #0 /var/www/html/gaoauth/Google/Auth/AssertionCredentials.php(130): Google_Signer_P12->__construct(‘{? “private_ke…’, ‘notasecret’) #1 /var/www/html/gaoauth/Google/Auth/AssertionCredentials.php(107): Google_Auth_AssertionCredentials->makeSignedJwt(Array) #2 /var/www/html/gaoauth/Google/Auth/OAuth2.php(306): Google_Auth_AssertionCredentials->generateAssertion() #3 /var/www/html/gaoauth/index.php(35): Google_Auth_OAuth2->refreshTokenWithAssertion(Object(Google_Auth_AssertionCredentials)) #4 {main} thrown in /var/www/html/gaoauth/Google/Signer/P12.php on line 70

  • San

    Please anyone help me its urgent and mail me the code on my email id for fetching the data from google analytic regarding the calculating the numbers of view of my side

  • Nadia

    Hello all,
    Thank’s for this tutorial.

    How can I download the p12 file ? I don’t understand what you mean by [Location of key file]…

  • Sharad

    Hi Linda,

    I had just asked a question where you gave me reply to follow this tutorial, will if am stuck in getting this error when running locally:

    Fatal error: Uncaught exception ‘Google_IO_Exception’ with message ‘HTTP Error: Unable to connect: ‘fopen(compress.zlib://https://www.googleapis.com/analytics/v3/data/ga?ids=ga%3A89798036&start-date=2014-12-14&end-date=2014-12-14&metrics=ga%3Ausers%2Cga%3Asessions&dimensions=ga%3AuserType): …….

    Can you please guide me, where I am failing to do something.

    Thanks,
    Sharad Soni

    • Sharad

      Hi Linda,

      I have solved the issue by adding the following line:
      $client->setClassConfig(“Google_Http_Request”, “disable_gzip”, true);
      I don’t know is it a good practice to disable the gzip or not but it worked.

      Secondly, I would like to add some validation on iterating the rows:

      if (is_array($data->getRows()) || is_object($data->getRows())) {
      foreach ($data->getRows() as $row) {
      print “”.$row[0].””.$row[1].””.$row[2].””;
      }
      }

      Wrapped under if condition, as if it returns no rows in my case (date was not proper) there should not be any error.

  • LEV ILIN

    Hi Linda!
    Thanks for tutorial! But I have a problem :
    I have a lot of accounts in GA, where I am just a watcher, not admin. So I can’t grant access to my service account email. How can I get stats from this accounts?

    Thank you!

    • Linda Lawton

      Then you cant use a service account. You will need to use Oauth2.

      A service account email address has to be added to the Account though the Google Analytics Website, if you don’t own the account you cant add it. You could try and contact the owner see if they are willing to add it for you.

  • MJ

    Hi. I’ve run into three (probably noob) questions that i didn’t see addressed in the comments so far:

    1. Double checking that the src/Google folder should just be copied and included right along with my plugin files. Is that right? It doesn’t need to be saved on the server? or loaded into a php library or some such?
    2. How do I save the key outside the web root? i can place it outside public_html, but then how do I write the address to link to it? in the other examples in the comments, you have “c:” as the start to this, does that mean that i should keep it stored locally on my machine? how would i use my script from other machines?
    3. How are people accessing the error codes? do these appear in console or on the site directly if something is broken?

    I very much appreciate your help!

    • Linda Lawton Post author

      Defiantly not noob questions 🙂

      1. 1. src/Google folder will need to be accessed by your script so it will need to be on the server and the script will have to have the correct path to find it.
      2. 2. I suggest you look up some Linux tutorials on how to map files and how to change file permissions. Yes the file needs to be on the server I test on my local machine which is c:\
      3. 3. I am sorry i don’t know what you mean by error codes.
      • MJ

        Thanks! by error code i’m referring to all the “FATAL ERROR” and “WARNING” messages that people are referencing in the comments. My script just causes the content of my page to disappear and i get no clue about what went wrong. Makes it super tough to troubleshoot.

        • MJ

          I was able to find the error messages in the error_log.

          I am still running into a 403 (user does not have sufficient permissions) error and wonder if I need to change the ga number in this line:

          $data = $service->data_ga->get(“ga:89798036”, “2014-12-14”, “2014-12-14”, “ga:users,ga:sessions”, $params );

          Is that ‘89798036’ specific to your google analytics request? Should i change it for my request?

          thanks!

          • MJ

            That was exactly my problem. switched “ga:89798036” to “ga:MyViewID” and everything worked like a charm. thanks!

  • Massimo

    Hi Linda can you help me?:

    Fatal error: Uncaught exception ‘Google_Cache_Exception’ with message ‘Could not create storage directory: /tmp/Google_Client/84’ in /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/google-api-php-client/src/Google/Cache/File.php:154
    Stack trace:
    #0 /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/google-api-php-client/src/Google/Cache/File.php(139): Google_Cache_File->getCacheDir(‘3eba0df1a8a7011…’, true)
    #1 /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/google-api-php-client/src/Google/Cache/File.php(134): Google_Cache_File->getCacheFile(‘3eba0df1a8a7011…’, true)
    #2 /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/google-api-php-client/src/Google/Cache/File.php(95): Google_Cache_File->getWriteableCacheFile(‘3eba0df1a8a7011…’)
    #3 /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/google-api-php-client/src/Google/Auth/OAuth2.php(322): Google_Cache_File->set(‘3eba0df1a8a7011…’, ‘{“access_token”…’)
    #4 /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/index in /www/MW_qPRcycRIG/massimopiccioni.it/Test/AnalyticsAPITest/google-api-php-client/src/Google/Cache/File.php on line 154

  • Jeff

    Hi Linda,

    I got an error that /autoload.php couldn’t be found. I found it somewhere in github and put it in the right directory, but now it gives me:
    PHP Fatal error: Class ‘GuzzleHttp\Collection’ not found in /usr/lib/php/google-api-php-client/src/Google/Client.php on line 93

    I’m wondering what’s up. I thought I had the very latest version of the api, so why aren’t things working?

  • James

    Hi Linda can you help me please?:

    I just seem to get a Server error 500 when I run the code.
    Could this be my server? I’m not sure whats missing.

  • Abin John

    Hi Linda

    My aim is to fetch all my labels(INBOX, SENT, SPAM etc) and mail count in corresponding labels.
    I created a service account. But i want to get all my labels from abin.john@altd.in mail. The following is my code

    type) && $data->type == ‘service_account’) {

    $user_to_impersonate = ‘abin.john@altd.in’;

    $cred = new Google_Auth_AssertionCredentials(
    $Email_address, // it’s the client email
    array(‘https://www.googleapis.com/auth/gmail.readonly’, ‘https://www.googleapis.com/auth/drive’), // it’s google gmail scope
    $data->private_key, // here is the private key
    ‘notasecret’,
    ‘http://oauth.net/grant_type/jwt/1.0/bearer’,
    $user_to_impersonate
    );

    }

    $client = new Google_Client();

    $client->setAssertionCredentials($cred);

    if (!$client->getAuth()->isAccessTokenExpired()) {
    return false;
    }
    else {
    $client->getAuth()->refreshTokenWithAssertion($cred);
    }

    $service_token = json_decode($client->getAccessToken());

    $drive_service = new Google_Service_Drive($client);
    $files_list = $drive_service->files->listFiles(array())->getItems();

    $service = new Google_Service_Gmail($client);
    // Print the labels in the user’s account.
    $results = $service->users_labels->listUsersLabels();

    echo “”;print_r($results);exit;

    it shows an error
    Fatal error: Uncaught exception ‘Google_Auth_Exception’ with message ‘Error refreshing the OAuth2 token, message: ‘ in /var/www/teletracker/files/google_service_account/google-api-php-client-1.1.7/src/Google/Auth/OAuth2.php on line 364

    Google_Auth_Exception: Error refreshing the OAuth2 token, message: ‘{ “error” : “unauthorized_client”, “error_description” : “Unauthorized client or scope in request.” }’ in /var/www/teletracker/files/google_service_account/google-api-php-client-1.1.7/src/Google/Auth/OAuth2.php on line 364

    Could you please help me?

    • Linda Lawton Post author

      I am not sure that service accounts work with google play serves api. You are going to have to pre authorize it some how and its not something i have access to so i cant test it.

      You might want to try asking on Stackoverflow.com for help

  • Roberto

    Hello,
    I’ve created a web-site where every user can upload documents that are automatically loaded into a specific google drive space for each user, without needing to enter credentials every time. The gmail user of each user must already exist or I create it for the occasion, but it must be accessible through a graphical interface. Therefore, I use the google drive APIs and create, for each user, a service account and the credentials needed to connect to the existing user to load the files in this drive space.

    There is an initial page where the user confirms, once, at the beginning, the project (website)’s access to the user. It runs one time and then never again. This is the code:

    //PAGE 1
    define(‘DRIVE_SCOPE’, ‘https://www.googleapis.com/auth/drive’);
    $redirect_uri = ‘http://’ . $_SERVER[‘HTTP_HOST’] . $_SERVER[‘PHP_SELF’];
    session_start();
    $auth_file = “path of client_secret_xxxxxxx.json”;
    $client = new Google_Client();
    $client->setAuthConfig($auth_file);
    $client->setRedirectUri($redirect_uri);
    $client->setIncludeGrantedScopes(true);
    $client->addScope(DRIVE_SCOPE);
    $service = new Google_Service_Drive($client);
    if (isset($_GET[‘code’])) {
    $token = $client->fetchAccessTokenWithAuthCode($_GET[‘code’]);
    $client->setAccessToken($token);

    // store in the session also
    $_SESSION[‘upload_token’] = $token;

    // redirect back to the example
    //header(‘Location: ‘ . filter_var($redirect_uri, FILTER_SANITIZE_URL));
    exit(“Authentication made!”);
    }

    // set the access token as part of the client
    if (!empty($_SESSION[‘upload_token’])) {
    $client->setAccessToken($_SESSION[‘upload_token’]);
    if ($client->isAccessTokenExpired()) {
    unset($_SESSION[‘upload_token’]);
    }
    else {
    $authUrl = $client->createAuthUrl();
    }

    if (isset($authUrl))
    header(‘Location: ‘ . filter_var($authUrl, FILTER_SANITIZE_URL));

    Then there is a page I call when I want to do an operation of any kind: upload, download, read, etc. This is the authentication code that runs before the operation:

    //PAGE 2
    define(‘DRIVE_SCOPE’, ‘https://www.googleapis.com/auth/drive’);
    $email = “gmail account of user”
    $client = new Google_Client();
    // set the scope(s) that will be used
    $client->addScope(DRIVE_SCOPE);
    // this is needed only if you need to perform
    // domain-wide admin actions, and this must be
    // an admin account on the domain; it is not
    // necessary in your example but provided for others
    $client->setSubject($email);
    // set the authorization configuration using the 2.0 style
    $auth_file = “path of service-account.json”;
    $client->setAuthConfig($auth_file);

    Until recently it worked regularly, I created several users like this! It still works for users already created!

    For some time now, when I create a new user:
    – when I run the authentication page, I get an error:
    Error: invalid_scope
    You don’t have permission to access some scopes. Your project is trying to access scopes that need to go through the verification process. {invalid = [https://www.googleapis.com/auth/drive]} If you need to use one of these scopes, submit a verification request.
    If I join the “Risky Apps” group, this problem resolves, but not what follows.

    – When I try to do any operation on the drive, page 2 authentication does not return any error, but when it comes to perform the specific operation, even a simple “file list”, I get the following error:
    {“Error”: “unauthorized_client”, “error_description”: “Client is unauthorized to retrieve access tokens using this method.” }
    In short, I can not do anything on the gmail user drive.
    I found that if, on page2, comment the line “$client->setSubject ($email);” or I put the service account mail address, the procedure works, but it works in the service account drive, not in the gmail account.

    I would like the procedure to work and work in an existing gmail account, as it did before! Definitely Google has introduced some changes … Is this something that can be solved?
    Thank you.

  • Vignesh Ayyappan

    Hi Linda,

    Thanks for the tutorial.

    Does it work the similar way for creating/updating contacts using service account. I could find only one tutorial for this and that’s not working either. It’s giving me a bad request error.

    Here’s the link to that tutorial comment that I’ve posted.

    https://www.webfoobar.com/index.php/node/75#comment-198

    Do you happen to know how to work this around for contacts API.? It’d be really helpful.

    Thanks

    • Linda Lawton Post author

      Remember a service account is not you. So if it did work you would only be adding contacts to the Service accounts google contacts account. There is no way to share permissions to your personal Google contacts account so service accounts do not work with this api.

      You will need to go though Oauth2.

  • Adnan

    Hi ,
    what is ‘Location of key file’ here? i have multiple sheets in one google spreadsheet (e.g. sheet1, sheet2, sheet3,….). so, what is the solution of this problem.
    Please help me out.

    • Linda Lawton Post author

      keyfile is the file that you download from Google developer console. It has nothing to do with the sheets within a Google sheet that your going to have to check the api documentation for.

  • Ritesh

    Hi

    I am using v 2.2.1 for google-api-php-client and i am getting below error, do i have to declare any class, and how?

    Fatal error: Class ‘Google_Auth_AssertionCredentials’ not found in \google-api-php-client-master\test.php on line 28
    Please let me know , how to fix this?