1

I'm trying to implement a script that will iterate through each user on my domain and set a custom signature to match company requirements. According to the forum post here I can do this if I create an Apps Script run as a service account with domain-wide delegation. I've created my service account, and made sure the delegation is set to domain-wide. I also added the OAuth2 library to my project. Running this code with my own email address, I get the error message 'Access not granted or expired. (line 352, file "Service", project "OAuth2").' I tried reaching out to Google cloud support for help implementing OAuth2, and they sent me here. Could I get assistance getting this to work on my domain and move in the right direction?

My current code version:

var EMAIL = Session.getActiveUser().getEmail();

var SERVICEACCT = {
  clientID: PropertiesService.getScriptProperties().getProperty('clientId'),
  fileText: PropertiesService.getScriptProperties().getProperty('clientSecretFile'), 
  projectID: PropertiesService.getScriptProperties().getProperty('clientProjectID'),
  privateKeyID: PropertiesService.getScriptProperties().getProperty('privateKeyID'),
  privateKey: PropertiesService.getScriptProperties().getProperty('clientSecretKey'),
  clientEmail: PropertiesService.getScriptProperties().getProperty('clientEmail'),
  authURL: PropertiesService.getScriptProperties().getProperty('clientAuthURI'),
  tokenURL: PropertiesService.getScriptProperties().getProperty('clientTokenURI'),
  providerURL: PropertiesService.getScriptProperties().getProperty('providerCertURL'),
  clientURL: PropertiesService.getScriptProperties().getProperty('clientCertURL'),
  map : PropertiesService.getScriptProperties().getKeys()
};


function gmailSignatureImage() {
   Logger.log(SERVICEACCT.clientEmail);
    var email = EMAIL;

  var service = getDomWideDelegationService('Gmail: ', 'https://www.googleapis.com/auth/gmail.settings.sharing', email);

    var resource = { signature: '<div><strong>My signature image</strong></div>' +
          '<div><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Google_2015_logo.svg/251px-Google_2015_logo.svg.png" '+ 
          'alt="" border="0" /></div>' };

    var requestBody                = {};
    requestBody.headers            = {'Authorization': 'Bearer ' + service.getAccessToken()};
    requestBody.method             = "PUT";
    requestBody.contentType        = "application/json";
    requestBody.payload            = JSON.stringify(resource);
    requestBody.muteHttpExceptions = false;

    var emailForUrl = encodeURIComponent(email);
    var url = 'https://www.googleapis.com/gmail/v1/users/me/settings/sendAs/' + emailForUrl;
    var setSignatureResponse = UrlFetchApp.fetch(url, requestBody);
}


// these two things are included in the .JSON file that you download when creating the service account and service account key
    var OAUTH2_SERVICE_ACCOUNT_PRIVATE_KEY  = SERVICEACCT.privateKey;
    var OAUTH2_SERVICE_ACCOUNT_CLIENT_EMAIL = SERVICEACCT.clientEmail;


function getDomWideDelegationService(serviceName, scope, email) {

    Logger.log('starting getDomainWideDelegationService for email: ' + email);

    return OAuth2.createService(serviceName + email)
    // Set the endpoint URL.
    //.setTokenUrl('https://accounts.google.com/o/oauth2/token')
      .setTokenUrl(SERVICEACCT.tokenURL)
    // Set the private key and issuer.
    .setPrivateKey(OAUTH2_SERVICE_ACCOUNT_PRIVATE_KEY)
    .setIssuer(OAUTH2_SERVICE_ACCOUNT_CLIENT_EMAIL)

    // Set the name of the user to impersonate. This will only work for
    // Google Apps for Work/EDU accounts whose admin has setup domain-wide
    // delegation:
    // https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
    .setSubject(email)

    // Set the property store where authorized tokens should be persisted.
    .setPropertyStore(PropertiesService.getScriptProperties())

    // Set the scope. This must match one of the scopes configured during the
    // setup of domain-wide delegation.
    .setScope(scope);

 }

Also, here are the results of printing my SERVICEACCT object to console (sanitized for privacy):

[17-03-28 13:32:13:515 EDT] Service Account
[17-03-28 13:32:13:515 EDT] Client ID: 1234567891011121314
[17-03-28 13:32:13:516 EDT] Project ID: project-id-12345678910112
[17-03-28 13:32:13:516 EDT] Private Key ID: 871**CONFIDENTIAL DATA**ad60
[17-03-28 13:32:13:517 EDT] Client Email: gsig-828@project-id-[Project ID].iam.gserviceaccount.com
[17-03-28 13:32:13:518 EDT] Auth URI: : https://accounts.google.com/o/oauth2/auth
[17-03-28 13:32:13:518 EDT] Token URI: https://accounts.google.com/o/oauth2/token
[17-03-28 13:32:13:519 EDT] Provider Certification URL: https://www.googleapis.com/oauth2/v1/certs
[17-03-28 13:32:13:519 EDT] Client Certification URL: https://www.googleapis.com/robot/v1/metadata/[projectID].iam.gserviceaccount.com
[17-03-28 13:32:13:519 EDT] Private Key: 
--------------------------------------------------------------------------------------------------------------------------------------
-----BEGIN PRIVATE KEY-----***CONFIDENTIAL KEY***\n-----END PRIVATE KEY-----\n
--------------------------------------------------------------------------------------------------------------------------------------
Rubén
  • 34,714
  • 9
  • 70
  • 166
Nathaniel MacIver
  • 387
  • 1
  • 4
  • 21

2 Answers2

0

Make sure that your Service is authorized. You may refer with this related thread which suggested to reset the service / clear your use properties. Google only returns the refresh token the first time you authorize the service, so if it was lost then it won't be restored in future authorizations. Also, try revoking access for this script / project and reauthorizing.

I have revoked all access and then I generated the license again far it works, I'll wait a while and see if it does not expire again.

Once you give permission not remove access to the application. I guess with this permission Google refresh the token.

Here's another SO post which might help: Automated OAuth2 token not working - Google Apps Script

Community
  • 1
  • 1
abielita
  • 13,147
  • 2
  • 17
  • 59
  • Since I am very new to Google OAuth2 authentication, I'm going to have to take this one step at a time.... When you say 'revoke access,' do you mean to delete the service account and create a new one? I'm looking at the properties of the service account I made and I can disable G-Suite domain authentication, create a key, or delete the account. Should I create a new key? – Nathaniel MacIver Mar 30 '17 at 04:32
0

Have you added Service Account to Domain Wide Delegation on Google Admin?

If not then you have to do it for the Script to have access. https://admin.google.com/

Or try this link https://admin.google.com/ac/owl/domainwidedelegation directly. You need to add there all privilages that your client will need to set up those actions.

I had the same issue and it solved it for me.

Apart from that I think your code looks ok.

Damian
  • 138
  • 6