Insufficient authentication scopes for domain-wide delegation

155 views
Skip to first unread message

Paul Heft

unread,
Oct 13, 2022, 1:42:34 AM10/13/22
to Google Apps Script Community
I am designing a Google Apps Script for domain-wide delegation, so that it can read details from Gmail in our Google Workspace domain's user accounts. The script fails even when it accesses my own Gmail. Thanks for looking at it!

"message": "Request had insufficient authentication scopes."
"errors ... ""message": "Insufficient Permission"
"reason": "ACCESS_TOKEN_SCOPE_INSUFFICIENT"

Being a super admin for our domain, I performed all the steps that follow.
My script is associated with a Google Cloud Platform (GCP) standard project.
I created a service account with access to the project. My roles: Project IAM Admin , Service account admin, Service account user, Service Account Token Creator.
The script includes the OAuth2 library.

OAuth 2.0 Scopes:
· "https://www.googleapis.com/auth/script.external_request"
· "https://www.googleapis.com/auth/gmail.labels" (Gmail API)
· "https://www.googleapis.com/auth/admin.directory.user.readonly" (Admin SDK API)
Admin SDK API is for another function which I will test next; it is not used currently.

The above scopes are set as follows:
· Project manifest (appsscript.json)
· OAuth consent screen for the project
· Domain-wide delegation: Admin console > Security > API Controls > Domain-wide Delegation
· Enable APIs for the standard Google Cloud project: Gmail, Admin SDK
· The service account has "Trusted" access ( Admin console > Security > Access and data control > API controls > Manage Third-Party App Access > App Access Control ) to Gmail and external request, but not to Admin SDK (not currently used).
· Set scopes in Code.gs: setScope refers to the first two scopes (Admin SDK is not currently used).

Script:

// Email address of the user to impersonate.
var USER_EMAIL = 'i...@domain.org'; // use my address for testing the simplest case


function listLabels() {
  /**
  * References:
  * https://developers.google.com/gmail/api/reference/rest/v1/users.labels/list
  * https://gmail.googleapis.com/$discovery/rest?version=v1
  * Similar script: https://developers.google.com/apps-script/advanced/gmail#list_label_information
  */
  try {
    const userID = '1x0gk371hhfknr'; // use my userID for now;
    var service = getService_('listLabels');
    if (service.hasAccess()) {
      var url = 'https://gmail.googleapis.com/gmail/v1/users/' + userID + '/labels';
      Logger.log(url);
// Script fails here:
      var response = UrlFetchApp.fetch(
        url, {
          headers: { Authorization: 'Bearer ' + service.getAccessToken() },
          muteHttpExceptions: true
        }
      );
      Logger.log('response: '+ response);
      var result = JSON.parse(response.getContentText());
      Logger.log("result['labels']: " + JSON.stringify(result['labels'], null, 2));
      for (let i = 0; i < result['labels'].length; i++) {
        const label = result['labels'][i];
        Logger.log(JSON.stringify(label));
      }
    } else {
      Logger.log( 'Service lacks access' );
    }
  } catch (err) {
    Logger.log('listLabels failed with: ' + err);
  }
}

function getService_( serviceName ) {
  /*
  * From https://github.com/googleworkspace/apps-script-oauth2/blob/main/samples/GoogleServiceAccount.gs
  * Implements domain-wide delegation
  */
  return OAuth2.createService(serviceName)
    .setTokenUrl('https://oauth2.googleapis.com/token')
    .setPrivateKey(PRIVATE_KEY)
    .setIssuer(CLIENT_EMAIL)
    .setSubject(USER_EMAIL) // name of the user to impersonate
  // Set the property store where authorized tokens should be persisted.
    .setPropertyStore(PropertiesService.getScriptProperties())
    .setScope(
      "https://www.googleapis.com/auth/script.external_request",
      "https://www.googleapis.com/auth/gmail.labels"
    )
}

// Private key and client email of the service account.
const PRIVATE_KEY =
  "-----BEGIN PRIVATE KEY-----\nMIIEv ... YNmQGU19FAcc=\n-----END PRIVATE KEY-----\n";
const CLIENT_EMAIL = "fifth-try@ ... .iam.gserviceaccount.com";

Reply all
Reply to author
Forward
0 new messages