Google Admin SDK: You do not have access to this API

Ever since Google Auth was disconnected last week, I have been trying to get oAuth 2.0 to work with a service account. We want to provide opportunism to users in our internal web application to install Out of Office there.

I downloaded the latest Google APIs Client Library for PHP . In the Google Developer Console, I created a new project for my application and created the Service account credentials. I also enabled the API: Admin SDK in the developer console.

enter image description here

I have granted account user id access to the correct areas (I think): enter image description here

When I use the service-account.php example and change the details, I get JSON with an access token, but when I make a CURL request (as before) to get the email settings from the user, the error "You are not authorized to access this API." .

My code is:

 <?php include_once "templates/base.php"; require_once realpath(dirname(__FILE__) . '/../src/Google/autoload.php'); $client_id = '124331845-DELETEDPART-hbh89pbgl20citf6ko.apps.googleusercontent.com'; //Client ID $service_account_name = ' 124331845-DELETEDPART-89pbgl20citf6ko@developer.gserviceaccount. com'; //Email Address $key_file_location = 'globaltext-4ce09b20cb73.p12'; //key.p12 $client = new Google_Client(); if (isset($_SESSION['service_token'])) { $client->setAccessToken($_SESSION['service_token']); } $key = file_get_contents($key_file_location); $cred = new Google_Auth_AssertionCredentials( $service_account_name, array('https://apps-apis.google.com/a/feeds/emailsettings/2.0/'), $key ); $client->setAssertionCredentials($cred); if ($client->getAuth()->isAccessTokenExpired()) { $client->getAuth()->refreshTokenWithAssertion($cred); } $aOutput = json_decode($client->getAccessToken()); $strEmailAdresSplit = explode('@', " FIRSTNAME.LASTNAME@DOMAIN.EXTENSION "); $strDomein = $strEmailAdresSplit[1]; $strAlias = $strEmailAdresSplit[0]; $resConnectionJobs = curl_init(); $aHeader = array(); $aHeader[] = 'Authorization: Bearer '.$aOutput->access_token; $aHeader[] = 'Content-Type: application/atom+xml'; curl_setopt($resConnectionJobs, CURLOPT_URL, "https://apps-apis.google.com/a/feeds/emailsettings/2.0/DOMAIN.EXTENSION/FIRSTNAME.LASTNAME/vacation"); curl_setopt($resConnectionJobs, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($resConnectionJobs, CURLOPT_HTTPHEADER, $aHeader); curl_setopt($resConnectionJobs, CURLOPT_RETURNTRANSFER, true); curl_setopt($resConnectionJobs, CURLOPT_HEADER, false); $oCurlData = curl_exec($resConnectionJobs); curl_close($resConnectionJobs); echo $oCurlData; ?> 
+5
source share
2 answers

Are you sure your credentials are OK?

Please try the following procedure to make sure you have the correct credentials.

Creating API Keys

Go to the developer console and do the following:

  • Choose your project
  • Select the menu item "API and auth"
  • Select the menu item "Registered application"
  • Register a web application type
  • Choose one of the following options, depending on which application you are creating. Server languages ​​should use this option:
    • Key for server applications (with IP blocking)

Obtaining an access token and updating a token

Create a file containing the following code:

 <?php if (isset($_GET['code'])) { // try to get an access token $code = $_GET['code']; $url = 'https://accounts.google.com/o/oauth2/token'; $params = array( "code" => $code, "client_id" => YOUR_CLIENT_ID, "client_secret" => YOUR_CLIENT_SECRET, "redirect_uri" => 'http://' . $_SERVER["HTTP_HOST"] . $_SERVER["PHP_SELF"], "grant_type" => "authorization_code" ); $ch = curl_init(); curl_setopt($ch, constant("CURLOPT_" . 'URL'), $url); curl_setopt($ch, constant("CURLOPT_" . 'POST'), true); curl_setopt($ch, constant("CURLOPT_" . 'POSTFIELDS'), $params); $output = curl_exec($ch); $info = curl_getinfo($ch); curl_close($ch); if ($info['http_code'] === 200) { header('Content-Type: ' . $info['content_type']); return $output; } else { return 'An error happened'; } } else { $url = "https://accounts.google.com/o/oauth2/auth"; $params = array( "response_type" => "code", "client_id" => YOUR_CLIENT_ID, "redirect_uri" => 'http://' . $_SERVER["HTTP_HOST"] . $_SERVER["PHP_SELF"], "scope" => "https://www.googleapis.com/auth/plus.me" ); $request_to = $url . '?' . http_build_query($params); header("Location: " . $request_to); } 

Now replace YOUR_CLIENT_ID and YOUR_CLIENT_SECRET with your client ID and client secret.

Verify that the scope is correct. For example, it should be https://www.googleapis.com/auth/analytics if you want to access Google Analytics.

If you run the file, you should get an OAuth2 confirmation screen.

If you now click Accept , you should get a result that looks like this:

 { "access_token" : YOUR_ACCESS_TOKEN, "token_type" : "Bearer", "expires_in" : 3600, "refresh_token" : YOUR_REFRESH_TOKEN } 

The result may contain additional fields, depending on which area you are applying for.


Connecting to Google systems in the background

As soon as you work on it, your application needs to implement the following workflow:

1) Check if your input contains a GET parameter named "code". If there is a β€œcode”, get a new access token and repeat this step (refresh the page) If there is no β€œcode”, go to step 2.

2) Check if you have credentials stored for your service. If credentials are present, check if your access token has expired or will expire soon. Then go to step 3. If there is no credential, go to the auth path of your service to get the authentication code and go back to step 1 (make sure Google redirects your current URL).

3) If an update is required, refresh the page and return to step 1. If an update is not required, you are ready to actually do what you wanted to do first.


The Google PHP library takes care if oAuth2 stream is for you, however. If you use your library, each of the steps in the three-step process takes care of this library, and you should just be able to do whatever you want with Google services right away. I use this strategy myself in my Google Adwords toolbar .

However, you can simply write your own library and directly contact it. Below is some developer code from a project that I wrote a few months ago. Although this does not work out of the box (since it is a controller that is part of a larger application), it should help you understand the flow that the Google library takes care of under the hood.

 namespace Application; class Controller_API_Google_Youtube extends Controller_API { public function read() { $scope = "https://www.googleapis.com/auth/youtube"; $this->doOauth($scope); } function doOauth($scope) { $oauth2Credentials = JSON_File::load(__DIR__ . DIRECTORY_SEPARATOR . 'Config.json'); $paths = array( 'token' => 'https://accounts.google.com/o/oauth2/token', 'auth' => "https://accounts.google.com/o/oauth2/auth" ); $refreshtime = 300; if (isset($_GET['code'])) { // Get access code $query = $_GET; unset($query['code']); if (count($query) > 0) { $query = '?' . http_build_query($query); } else { $query = ''; } $client = \PowerTools\HTTP_Client::factory( array( 'maps' => array( 'url' => $paths['token'], 'returntransfer' => 1, 'post' => true, 'postfields' => array( 'code' => $_GET['code'], "client_id" => $oauth2Credentials['client_id'], "client_secret" => $oauth2Credentials['client_secret'], "redirect_uri" => HTTP_PROTOCOL . URL_PATH . $query, "grant_type" => "authorization_code" ) ) ) )->execute(); $responses = $client->getResponses(); $response = array_pop($responses); $info = $response['maps']->getInfo(); $content = $response['maps']->getContent(); if ($info['http_code'] === 200) { $output = JSON::decode($content); $oauth2Credentials[$scope] = array(); $oauth2Credentials[$scope]['expires'] = time() + $output['expires_in']; $oauth2Credentials[$scope]['access_token'] = $output['access_token']; $oauth2Credentials[$scope]['refresh_token'] = $output['refresh_token']; file_put_contents(__DIR__ . DIRECTORY_SEPARATOR . 'Config.json', JSON::encode($oauth2Credentials)); header("Location: " . HTTP_PROTOCOL . URL_PATH . $query); } else { echo "Something went wrong"; } } elseif (!isset($oauth2Credentials[$scope])) { // Get auth code header("Location: " . $paths['auth'] . '?' . http_build_query( array( "response_type" => "code", "client_id" => $oauth2Credentials['client_id'], "redirect_uri" => HTTP_PROTOCOL . DOMAIN_PATH, "scope" => $scope ) )); } elseif ($oauth2Credentials[$scope]['expires'] - $refreshtime < time()) { // Refresh access code $client = \PowerTools\HTTP_Client::factory( array( 'maps' => array( 'url' => $paths['token'], 'returntransfer' => 1, 'post' => true, 'postfields' => array( "client_id" => $oauth2Credentials['client_id'], "client_secret" => $oauth2Credentials['client_secret'], "refresh_token" => $oauth2Credentials[$scope]['refresh_token'], "grant_type" => "refresh_token" ) ) ) )->execute(); $responses = $client->getResponses(); $response = array_pop($responses); $info = $response['maps']->getInfo(); $content = $response['maps']->getContent(); if ($info['http_code'] === 200) { $output = JSON::decode($response['maps']->getContent()); $oauth2Credentials[$scope]['expires'] = time() + $output['expires_in']; $oauth2Credentials[$scope]['access_token'] = $output['access_token']; file_put_contents(__DIR__ . DIRECTORY_SEPARATOR . 'Config.json', JSON::encode($oauth2Credentials)); $this->read(); } else { $this->output = array("error" => "Something went wrong"); } } else { $this->doSomethinguseful($oauth2Credentials, $scope); } return $this; } function doSomethinguseful($oauth2Credentials, $scope) { // https://developers.google.com/youtube/v3/sample_requests?hl=nl $client = \PowerTools\HTTP_Client::factory( array( 'maps' => array( 'useragent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13', 'url' => 'https://www.googleapis.com/youtube/v3/channels?part=contentDetails&mine=true', 'returntransfer' => true, 'httpheader' => array( 'Authorization: Bearer ' . $oauth2Credentials[$scope]['access_token'], 'Accept-Encoding: gzip, deflate' ) ) ) )->execute(); $responses = $client->getResponses(); $response = array_pop($responses); $content = $response['maps']->getContent(); $this->output = JSON::decode(gzdecode($content)); } } 
+1
source

It looks like you are facing a problem that I am facing.

Calling the Google_Auth_AssertionCredentials function requires more parameters than you send to work with the service account. (At least that was in my case.)

You need to pass enough parameters to enable sub (which user should take action because of).

Without this, I always got access. This is clearly not obvious, since the loadServiceAccountJson function has been added to the php library, which should configure the client connection of the service account, but it breaks because it also does not install sub.

See the working code here: Google php client library loadServiceAccountJson broken - fixed in bundle

-1
source

All Articles