Infitialis Blog

View me on GitHub

Domain Wide Delegation Tokens from PHP

06 Jul 2020

We recently had a requirement to communicate with Google’s AdWords API from an application on App Engine, which proved to be frustrating when it came to implementing authentication, as documented in the AdWords PHP library.

By default, they recommend using OAuth2 credentials obtained in a client-server authentication flow, then saving the refresh token and client ID details inside an ini file which needs to be readable by the application.

They did support server-to-server auth flows using Domain Wide Delegation, but only when using a service account JSON key file.

Both of these methods went against the established methodology for App Engine and the rest of Google Cloud, where the convention is to use trust provided by the environment, in the form of tokens from the metadata server and the default service account.

I had already crossed this bridge in Go, but in the legacy App Engine first generation runtimes, then again in the Second Generation runtimes with the help of another user on GitHub.

I started looking at how to accomplish the same thing in PHP and it was actually fairly straight forward:

As far as I can tell, the OAuth2 class doesn’t expose the right options to be able to use it natively (it only support a sign key option, where what we really need is a signer interface, or callback function), but we can extend it fairly easily.

My code is included in GaeSupportLaravel, but can be pulled into other projects fairly easily as it’s a small class, also making use of the IAMSigner class we created in one of my last posts, for signing JWTs with the Service Account Credentials API.

To use this with AdWords, a real world code example changes from this:

use Google\AdsApi\Common\OAuth2TokenBuilder;

...

    protected function __getAdWordsClient()
    {
        $oAuth2Credential = (new OAuth2TokenBuilder())->fromFile(__DIR__ . '/adsapi_php.ini')->build();
        return (new AdWordsSessionBuilder())->fromFile(__DIR__ . '/adsapi_php.ini')->withOAuth2Credential($oAuth2Credential)->build();
    }

...

To this:

use A1comms\GaeSupportLaravel\Integration\JWT\TokenSource\DWDTokenSource;

...

    protected function __getAdWordsClient()
    {
        $oAuth2Credential = new DWDTokenSource(env('ADWORDS_USER_EMAIL'), ['https://www.googleapis.com/auth/adwords']);
        return (new AdWordsSessionBuilder())->fromFile(__DIR__ . '/adsapi_php.ini')->withOAuth2Credential($oAuth2Credential)->build();
    }

...

And the adsapi_php.ini file no longer contains any credentials, only the developerToken.

I’ve opened tickets in both Google’s auth library and the AdWords API library.