Home > database >  API suddently started throwing Error: Access not granted or expired. Service_.getAccessToken Service
API suddently started throwing Error: Access not granted or expired. Service_.getAccessToken Service

Time:04-08

I am currently running some script on Google script to call the Salesforce REST API and download the data into Google Sheets.

I am using the Google Sheets library id 1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF, which is the OAuth2 Library which can be found on github here.

I then, as instructed, use the following call to actually authenticate the Salesforce API with the following code:

var CLIENT_ID = {I get this from the connected SalesForce app};
var CLIENT_SECRET = {I get this from the connected SalesForce app};

function getService() {
  // Create a new service with the given name. The name will be used when
  // persisting the authorized token, so ensure it is unique within the
  // scope of the property store.
  return OAuth2.createService('salesforce')
      // Set the endpoint URLs
      .setAuthorizationBaseUrl('https://flolive.my.salesforce.com/services/oauth2/authorize')
      .setTokenUrl('https://flolive.my.salesforce.com/services/oauth2/token')
      

      // Set the client ID and secret, from the Google Developers Console.
      .setClientId(CLIENT_ID)
      .setClientSecret(CLIENT_SECRET)

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

      // Set the property store where authorized tokens should be persisted.
      .setPropertyStore(PropertiesService.getDocumentProperties())
       // .setCache(CacheService.getDocumentCache())
      // Set the scopes to request (space-separated for Google services).
    
     // .setScope('r_organization_social,r_basicprofile,r_liteprofile,rw_organization_admin,r_ads_reporting,r_ads')

      // Below are salesforce-specific OAuth2 parameters.

        .setParam('response_type', 'code')
      
      // Forces the approval prompt every time. This is useful for testing,
      // but not desirable in a production application.
      //.setParam('approval_prompt', 'force');
}

function authCallback(request) {
  var salesforceService = getService();
  var isAuthorized = salesforceService.handleCallback(request);
  if (isAuthorized) {
    return HtmlService.createHtmlOutput('Success! You can close this tab.');
  } else {
    return HtmlService.createHtmlOutput('Denied. You can close this tab');
  }
}

function logOut() {
  PropertiesService.getDocumentProperties().deleteAllProperties();
  PropertiesService.getUserProperties().deleteAllProperties();
  var service=getService();
    service.reset();

}
function salesforceAPI() {
  var service = getService();
  if (service.hasAccess()) {
    //exchange authorisation code for access token
    
    // sheet.getSheetByName('Settings').getRange(3,2).setValue(getService().getAccessToken());

    var tokenURL = 'https://flolive.my.salesforce.com/services/oauth2/token';

    var parameters = 'grant_type=authorization_code&code=' getService().getAccessToken() '&redirect_uri=' getService().redirect_uri '&client_id=' CLIENT_ID '&client_secret=' CLIENT_SECRET;

 var options = {
   'method': 'POST',
   'contentType': 'application/x-www-form-urlencoded',
  'muteHttpExceptions': true,    
   'payload': parameters
  }

  var response = UrlFetchApp.fetch(tokenURL,options);
  var json = JSON.parse(response.getContentText());

  console.log(json);

    //sheet.getSheetByName('Settings').getRange(3,3).setValue(json.items);
  return json;

    
  } else {
    var authorizationUrl = service.getAuthorizationUrl();
    var template = HtmlService.createTemplate(
        '<a href="<?= authorizationUrl ?>" target="_blank">Authorize</a>. '  
        'Reopen the sidebar when the authorization is complete.');
    template.authorizationUrl = authorizationUrl;
    var page = template.evaluate();
    SpreadsheetApp.getUi().showModalDialog(page,'Authorise salesforce');

    Logger.log(getService().getAccessToken());
  }
}

Now I didn't have a problem with this. All the calls I made worked. I checked the callback url in the connected app, and everything was fine.

When I tried to output some of the data to a different worksheet, things stopped working.

So now I have 2 worksheets.

SF API Backend - This is where I put all the settings and references for the API Logged Meetings - This is where I output the data that I'm trying to pull, which are the activities.

At first everything worked and I could output properly. However, when I added the API backend worksheet, at first it didn't work. I didn't get any errors, no data got pulled in.

I thought it was because it needed a different callback url, so I added it. Then, for some reason, I used the logOut() function mentioned above to try and reset the connection. That's when I started getting this error Error: Access not granted or expired. Service_.getAccessToken @ Service.gs:466.

I looked online and thought it had something to do with the PropertyService. So I deleted all the PropertyService keys. I even switched in the getService() function from .setPropertyStore(PropertiesService.getDocumentProperties()) to .setCache(CacheService.getDocumentCache()) (which is now commmented out).

Still the same error.

Then I went into Salesforce and get a set access token and replaced getService().getAccessToken() with that.

I get this error TypeError: Cannot read property 'setClientId' of undefined at getService(SalesForceAuthentication:15:7) at salesforceAPI(SalesForceAuthentication:56:17)

I'm not sure why I get that error, since the code I changed wasn't even in that function.

And that's currently where I am.

I don't see anything blacklisted or any settings that would mess around or block this.

I even tried rebuilding the entire thing and then copying the code (only the code) to a different script. I got the same error Error: Access not granted or expired. Service_.getAccessToken @ Service.gs:466.

This leads me to think that the Client Secret/Client Id is being blocked somehow.

CodePudding user response:

Issue:

When you use getDocumentProperties() to store the authorization data:

Gets a property store (for this script only) that all users can access within the open document, spreadsheet, or form

The data is not available if you use a different spreadsheet than the one where it was stored.

Solution:

If you want this to work for multiple spreadsheets, use getScriptProperties() or getUserProperties() instead, which can persist on multiple documents (only if you're using the same script).

.setPropertyStore(PropertiesService.getScriptProperties())
  • Related