Search code examples
google-apps-scriptgoogle-sheetsoauth-2.0add-on

Oauth 2.0 problem after publish apps script to add-ons


I'm working on Integrate Google spreadsheet with Salesforce using Google AppsScript.

https://github.com/googleworkspace/apps-script-oauth2

I proceeded with the OAuth2.0 authorization by referring to the above and confirmed that it was working normally.

The problem happened after I published the Google Apps script as a Google Workspace add-ons. (App Visbility is Priavte -Only available to users in your domain.)

When multiple people download the add-ons and proceed with authorization, the credentials(OAuth2.0 access token, OAUth2.0 instance_url) of all downloaded people are changed to the credentials(OAuth2.0 access token, OAUth2.0 instance_url) of the last person who authenticated.

for example

A person named Olivia downloads add-ons and login in to org called A.salesforce.com, then a person named Lucas downloads add-ons and login in to org called B.salesforce.com

Then Olivia's credentials will also be replaced by the credentials of B.salesforce.com where Lucas logged in.

I don't know why this is happening.

Is there any part of the code that needs to be modified?

function run() {
  var service = getService_();
  if (service.hasAccess()) {
   var url = service.getToken().instance_url +
    '/services/data/v24.0/chatter/users/me';

   // Make the HTTP request using a wrapper function that handles expired
  // sessions.
   var response = withRetry(service, function() {
     return UrlFetchApp.fetch(url, {
        headers: {
          Authorization: 'Bearer ' + service.getAccessToken(),
        }
     });
  });
  var result = JSON.parse(response.getContentText());
  } else {
     openUrl()
  }
}

function withRetry(service, func) {
  var response;
  var content;
  try {
    response = func();
    content = response.getContentText();
  } catch (e) {
    content = e.toString();
  }
  if (content.indexOf('INVALID_SESSION_ID') !== -1) {
    service.refresh();
    return func();
  }
  return response;
}

/**
 * Reset the authorization state, so that it can be re-tested.
*/
function reset() {
  getService_().reset();
}


/**
 * Configures the service.
 */
function getService_() {
  return OAuth2.createService('Saleforce')
      // Set the endpoint URLs.
   .setAuthorizationBaseUrl('https://login.salesforce.com/services/oauth2/authorize')
   .setTokenUrl('https://login.salesforce.com/services/oauth2/token')

   // Set the client ID and secret.
  .setClientId(CLIENT_ID)
  .setClientSecret(CLIENT_SECRET)

  // Set the name of the callback function that should be invoked to
  // complete the OAuth flow.
  .setCallbackFunction('authCallback')

  // Set the property store where authorized tokens should be persisted.

  .setPropertyStore(PropertiesService.getScriptProperties())
  

  // Set the scopes to be requested.
  //.setScope('chatter_api refresh_token');
}

/**
 * Handles the OAuth callback.
 */
function authCallback(request) {
  var service = getService_();
  var authorized = service.handleCallback(request);
  if (authorized) {
    return HtmlService.createHtmlOutput('Success!');
  } else {
    return HtmlService.createHtmlOutput('Denied.');
  }
}


/**
 * Open authorizationUrl
 */
function openUrl() {
  var service = getService_();
   var authorizationUrl = service.getAuthorizationUrl();
  var html = HtmlService.createHtmlOutput('<html><script>'
    + 'window.close = function(){window.setTimeout(function(). 
 {google.script.host.close()},9)};'
    + 'var a = document.createElement("a"); a.href="' + authorizationUrl + '"; 
a.target="_blank";'
    + 'if(document.createEvent){'
    + '  var event=document.createEvent("MouseEvents");'
    + '  if(navigator.userAgent.toLowerCase().indexOf("firefox")>-1). 
 {window.document.body.append(a)}'
    + '  event.initEvent("click",true,true); a.dispatchEvent(event);'
    + '}else{ a.click() }'
    + 'close();'
    + '</script>'
    // Offer URL as clickable link in case above code fails.
    + '<body style="word-break:break-word;font-family:sans-serif;">Failed to open 
  automatically. <a href="' + authorizationUrl + '" target="_blank" 
  onclick="window.close()">Click here to proceed</a>.</body>'
    + '<script>google.script.host.setHeight(40);google.script.host.setWidth(410). 
  </script>'
       + '</html>')
      .setWidth(90).setHeight(1);
      SpreadsheetApp.getUi().showModalDialog(html, "Open ...");
   }


/**
 * Logs the redict URI to register.
 */
function logRedirectUri() {
  Logger.log(OAuth2.getRedirectUri());
}

Solution

  • The problem occurs because the script is using the Script store (PropertiesService.getScriptProperties()) to store the OAuth authorization token. This could be fixed by using the User Store (PropertiesService.getUserProperties()) instead.

    Use the Script Store to store properties for all users

    Use the Document Store to store properties for each file no matter what user uses it.

    Use the User Store to store properties for each user, no matter what file is used