Switch from Google_Service_AnalyticsReporting (google/apiclient SDK) to BetaAnalyticsDataClient (google/analytics-data SDK)

Viewed 656

I am in the process of switching Google Analytics properties from UA to GA4 and am trying to pull Google Analytics data for GA4 properties using the Data API. I'm currently using the google/apiclient PHP SDK for UA properties but need to switch to the google/analytics-data SDK for GA4 properties. All the documentation I can find for credentials is written for using service accounts. Unfortunately, we cannot use a service account for our current setup and need to login as the user analytics@company.com which is the email/user that has been added on properties within our accounts.

For the google/apiclient SDK we make our connection like this:

$appName = 'My Analytics App';
// Decoded from json file for example
$clientAuthFileData = [
    'web' => [
        'client_id'                   => '######-#######.apps.googleusercontent.com',
        'project_id'                  => 'my-project-name',
        'auth_uri'                    => 'https://accounts.google.com/o/oauth2/auth',
        'token_uri'                   => 'https://oauth2.googleapis.com/token',
        'auth_provider_x509_cert_url' => 'https://www.googleapis.com/oauth2/v1/certs',
        'client_secret'               => 'XXXXXXXXXXX',
        'redirect_uris'               =>
            [
                'https://site1.com/authorize.php',
                'https://site2.com/authorize.php',
                'https://site3.com/authorize.php',
                'https://site4.com/authorize.php',
                'https://site5.com/authorize.php',
            ],
    ],
];
// Decoded from json file for example
$authFileData       = [
    'access_token'  => 'XXXXXXXX',
    'expires_in'    => 3600,
    'refresh_token' => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
    'scope'         => 'https://www.googleapis.com/auth/userinfo.email openid https://www.googleapis.com/auth/analytics.readonly',
    'token_type'    => 'Bearer',
    'id_token'      => 'XXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXXXXXX',
    'created'       => 1553570124,
];

$client = new Google_Client();
$client->setApplicationName( $appName );
$client->setAccessType( "offline" );
$client->setAuthConfig( $clientAuthFileData );
$client->fetchAccessTokenWithRefreshToken( $authFileData['refresh_token'] );

$client = new Google_Service_AnalyticsReporting( $client );

To do the same call using a service account in the google/analytics-data SDK it looks like this:

// Decoded from json file for example
$serviceAccountCredentials = '{
  "type": "service_account",
  "project_id": "my-project-name",
  "private_key_id": "XXXXXXXXXX",
  "private_key": "-----BEGIN PRIVATE KEY-----XXXXXXXXX\n-----END PRIVATE KEY-----\n",
  "client_email": "name@my-project-name.iam.gserviceaccount.com",
  "client_id": "XXXXXXXXXX",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/name%40my-project-name.iam.gserviceaccount.com"
}';

$client = new BetaAnalyticsDataClient( [
    'credentials' => json_decode( $serviceAccountCredentials, true ),
] );

For GA4, I've tried the following:

/*
THROWS
Fatal error: Uncaught InvalidArgumentException: json key is missing the type field in /var/www/html/vendor/google/auth/src/CredentialsLoader.php on line 150

InvalidArgumentException: json key is missing the type field in /var/www/html/vendor/google/auth/src/CredentialsLoader.php on line 150
*/
$client = new BetaAnalyticsDataClient( [
    'credentials' => $clientAuthFileData,
] );

/*
THROWS
Fatal error: Uncaught DomainException: Could not load the default credentials. Browse to https://developers.google.com/accounts/docs/application-default-credentials for more information in /var/www/html/vendor/google/gax/src/CredentialsWrapper.php on line 267
Google\ApiCore\ValidationException: Could not construct ApplicationDefaultCredentials in /var/www/html/vendor/google/gax/src/CredentialsWrapper.php on line 267
 */
$client = new BetaAnalyticsDataClient( [
    'keyFile' => $clientAuthFileData,
] );

How can I connect using the same OAuth details that are used by the google/apiclient SDK?

2 Answers

I manage to do the same thing without specifying scope's. I think it is not necessary as it is not written in the documentation and it is working fine for me. I only used my json file which is my server-side key.

$config = [
    'credentials' => [PATH-TO-JSON-FILE],
];

$client = new BetaAnalyticsDataClient($config);

FIgured this out by digging through the class files on how they handle credentials. For anyone else who runs into this you can use this:

$client = new BetaAnalyticsDataClient( [
    'credentials' => Google\ApiCore\CredentialsWrapper::build( [
        'scopes'  => [
            'https://www.googleapis.com/auth/analytics',
            'openid',
            'https://www.googleapis.com/auth/analytics.readonly',
        ],
        'keyFile' => [
            'type'          => 'authorized_user',
            'client_id'     => $clientAuthFileData['web']['client_id'],
            'client_secret' => $clientAuthFileData['web']['client_secret'],
            'refresh_token' => $authFileData['refresh_token'],
        ],
    ] ),
] );

I'm setting the scope here as an array since that's the way the class is expecting it and in the JSON files they are a string separated with spaces, you could probably use the following but I didn't test it:

$client = new BetaAnalyticsDataClient( [
    'credentials' => Google\ApiCore\CredentialsWrapper::build( [
        'scopes'  => explode( ' ', $authFileData['scope'] ),
        'keyFile' => [
            'type'          => 'authorized_user',
            'client_id'     => $clientAuthFileData['web']['client_id'],
            'client_secret' => $clientAuthFileData['web']['client_secret'],
            'refresh_token' => $authFileData['refresh_token'],
        ],
    ] ),
] );
Related