Search code examples
google-apps-scriptgoogle-secret-manager

Private key not working when using Google Secrets Manager in Apps Script


I have a Google Apps Script application that uses a service account with domain-wide delegation to make changes to user accounts on a domain. To improve the security of the application, I moved from storing the private key in code to using Google Secrets Manager with this answer. Strangely, I could see the key being returned correctly from secrets manager but it would fail to get an authorized token, throwing the following error:

{ [Exception: Invalid argument: key] name: 'Exception' }

Solution

  • I solved the issue after seeing this comment in the GitHub repo. I just added the replacement to the retrieval function and everything resumed working correctly. I also cleared the script properties to ensure I was pulling new tokens correctly.

    function getSecret() {
      let token, endpoint, response;
      endpoint = `https://secretmanager.googleapis.com/etc etc etc`;
      token = ScriptApp.getOAuthToken();
      response = UrlFetchApp.fetch(endpoint, {
        headers: {
          Authorization: 'Bearer ' + token,
          Accept: 'application/json',
        }
      });
      var decodedAPIKey = Utilities.base64Decode(JSON.parse(response.getContentText())['payload']['data']);
      var apiKey = Utilities.newBlob(decodedAPIKey).getDataAsString();
      return apiKey;
    }
    
    function getSerivce(targetEmail,scopes) {
      console.log("trying to get oauth2 service with:\n"+scopes);
      PRIVATE_KEY = getSecret().replace(/\\n/g, '\n');
      return OAuth2.createService('Gmail:' + boxEmail)
        // Set the endpoint URL.
        .setTokenUrl('https://oauth2.googleapis.com/token')
    
        // Set the private key and issuer.
        .setPrivateKey(PRIVATE_KEY)
        .setIssuer(CLIENT_EMAIL)
    
        // Set the name of the user to impersonate.
        .setSubject(targetEmail)
    
        // 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(scopes);
    }