Authentication error when attempting to fetch google analytics 4 with app script

Viewed 565

I would like to connect a community connector to a google analytics 4 account so that I can easily modify the data and send it to data studio. However, My code is returning an authentication error:

{ error: 
   { code: 401,
     message: 'Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.',
     status: 'UNAUTHENTICATED' } }

I have included the token, but I am unsure if I am making the correct url call or if there is some other issue that I am unaware of. I don't believe I need an API key to connect from community connector to a google API, but I may be wrong. I did create an API key but the result was the same.

function testFetch(){
  var url = "https://analyticsdata.googleapis.com/v1alpha:runReport"
  var token = ScriptApp.getOAuthToken();
 
  var options = {
      "method" : 'POST',
      "entity": { "propertyId": "263290444" },
      "dateRanges": [{ "startDate": "2020-12-01", "endDate": "2021-03-01" }],
      "dimensions": [{ "name": "country" }],
      "metrics": [{ "name": "activeUsers" }],
      'muteHttpExceptions': true,
      headers: {
          Authorization: 'Bearer' + token,
        },
      };

  var response = UrlFetchApp.fetch(url, options);

  var result = JSON.parse(response.getContentText());
}
1 Answers

Here is a small guide on how to do what you are trying to achieve:

Set explicit OAuth scopes (see documentation) to your Apps Script project manifest (appsscript.json). In this case you need to add the following:

{
  ...
  "oauthScopes": [
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/analytics.readonly"
  }
}

Then you need to separate the method parameters from the fetch options. The fetch options need to be stringified and added to payload. You also need to set the contentType to JSON.

const options = {
  entry: { propertyId: "263290444"},
  // etc.
}
const response = UrlFetchApp.fetch(
  'https://analyticsdata.googleapis.com/v1alpha:runReport',
  {
    method: 'POST',
    muteHttpExceptions: true,
    headers: {
      'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
    },
    contentType: 'application/json; charset=utf-8',
    payload: JSON.stringify(options)
  }
)

After that, you may use the response as you were doing before.

Note that Bearer and the token need to be separated by a space, which your code does not have. It's hard to see because of the concatenation and that why I usually use template literals (see documentation).

References

Related