0
votes

@note The involved server flow uses google-api-php-client-beta

The goal is to 'insert' an email 'message' into a Google for Work gmail account addressed to a registered email alias.

For this OAuth workflow, I have:

  • a Google for Work User with an email alias on a registered add-on domain
  • created a 'Project' in console.developers.google.com/apis/
  • created a 'Service Account' under the Project
  • enabled the Account for 'domain-wide-access'
  • added an OAuth 'Client' to the Service Account, along with credentials downloaded as a JSON string
  • authorized the Client with 'scopes' in https://admin.google.com/my-domain.tld
  • an authorization code allowing the 'Project' to request 'Access Tokens' to do scopes on the User (requires separate single-use client)

The following server code attempts to acquire a Google_Client authorized with the above Credentials and Access Token, while asking for the OAuth Client to impersonate the GFW User mentioned. Thereafter the $client can be used to call services such as Google_Service_Gmail.

Currently, the $authCreds is returned with ['error_description'] => 'Could not determine client ID from request' error message

// local const's for testing
const CLNT_GOOGL_SRVC_ACCT_CREDS = '';
const CLNT_GOOGL_API_SRVC_ACCT_CLIENT_ACCESS_CODE = '';
/**
* Returns an authorized API client.
* @return Google_Client the authorized client object
*/
private static function getAuthorizedClient() {
    $client = new Google_Client();
    $isSrvcAcct = false;

    if (self::CLNT_GOOGL_SRVC_ACCT_CREDS) {
        $isSrvcAcct = true;
        $creds = json_decode(self::CLNT_GOOGL_SRVC_ACCT_CREDS, true);
    } elseif (defined('CLNT_GOOGL_SRVC_ACCT_CREDS')) {
        $isSrvcAcct = true;
        $creds = json_decode(CLNT_GOOGL_SRVC_ACCT_CREDS, true);
    }

    if ($isSrvcAcct) {
        if (! isset($creds)) {
            acapApp::catchProcessMessage('CLNT_GOOGL_SRVC_ACCT_CREDS  is not valid JSON?', ACAP_DEBUG);

            return;
        }

        self::setServiceClient($client, (array) $creds);
    } else {
        self::setUserClient($client);
    }

    if ($client->getAccessToken()) {
        return $client;
    }
}

private static function setServiceClient(Google_Client $client, array $creds) {
    $client->setAuthConfig($creds);
    $client->setSubject(CLNT_SMTP_OAUTH_USER_EMAIL);

    if (self::CLNT_GOOGL_API_SRVC_ACCT_CLIENT_ACCESS_CODE) {
        $authCode = self::CLNT_GOOGL_API_SRVC_ACCT_CLIENT_ACCESS_CODE;
    } else if (defined('CLNT_GOOGL_API_SRVC_ACCT_CLIENT_ACCESS_CODE')) {
        $authCode = CLNT_GOOGL_API_SRVC_ACCT_CLIENT_ACCESS_CODE;
    }

    if (isset($authCode)) {
        $authCreds = $client->fetchAccessTokenWithAuthCode($authCode);
        if (isset($authCreds['error'])) {
            acapApp::catchProcessMessage('Failure Fetching Auth Token: '.$authCreds['error_description'], ACAP_DEBUG);
        }
    }
}
2
I am not sure where you are getting CLNT_GOOGL_API_SRVC_ACCT_CLIENT_ACCESS_CODE, but service accounts / clients don't have auth codes. Only users do. - Brent Shaffer
In general this code is very hard to follow, but if you create an installed application or delegate user auth to a service account, you'll be good to go. - Brent Shaffer
the CLNT_* constants are provided by the framework from db store. They're descriptive enough to imagine the values. - CNSKnight
The referenced: 2. Create a "service account" and from your USER account, authorize the client so it shows up here - is complete as outlined above. Tho by USER acct I believe you mean API's Project. - CNSKnight
Did you already check this documentation about OAuth 2.0 for Server to Server Applications? Did you properly follow the guides here? - KENdi

2 Answers

1
votes

If you use the .json file u have to use this for auth: $client->fetchAccessTokenWithAssertion()

1
votes

Ensure that you're setting the authorisation config prior to fetching the access token with the auth code.

For example:

<?php
$client->setAuthConfig(storage_path('app/google_client_id.json'));
$token = $client->fetchAccessTokenWithAuthCode($code);