'Google Apps Script: Connecting to Amazon Selling Partner API (Access Token)

I'm trying to connect to Amazon Selling Partner API using Google Apps Script.

The first step based on the documentation is to generate an access token if we don't have one valid at the moment (Access tokens expire one hour after they have been generated).

For that we would need the following inputs:

  • grant_type (parameter)
  • refresh_token (input)
  • scope (parameter)
  • client_id (input)
  • client_secret (input)

I'm trying to generate an access token for an operation that requires seller authorization

Here is my code so far:

const REFRESH_TOKEN = "MyRefreshToken";
const CLIENT_ID ="MyClientID";
const CLIENT_SECRET = "MyClientSecret"

function AccessToken(){
  var base_url = 'https://api.amazon.com/auth/o2/token';
  var pointParams = "?grant_type=refresh_token&refresh_token=" + REFRESH_TOKEN + "&client_id=" + CLIENT_ID + "&client_secret=" + CLIENT_SECRET;
  var query_string = base_url + pointParams;

  var headers = {
    'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
    //'Host': 'api.amazon.com' (ignored since we already provided the url in the base_url var)
  }
  var options = {
    'method' : 'POST',
    'headers': headers,
    //'muteHttpExceptions': true

  };

  var rawData = UrlFetchApp.fetch(query_string, options).getContentText();
  Logger.log('rawData: ' + rawData)
}

Note: When we call an operation that requires seller authorization we will set the parameter grant_type = refresh_token and in this case the scope parameter should not be included

This is the example code provided by the website:

POST /auth/o2/token HTTP/l.l
Host: api.amazon.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
grant_type=refresh_token
&refresh_token=Aztr|...
&client_id=foodev
&client_secret=Y76SDl2F

PROBLEM

I'm getting a 500 server error:

Exception: Request failed for https://api.amazon.com returned code 500. Truncated server response: {} (use muteHttpExceptions option to examine full response) AccessToken @ API.gs:30

Using 'muteHttpExceptions': true only shows that the result of the UrlFetchapp is blank

QUESTIONS

Based on the documentation a 500 error is described as

There was an internal service failure.

However I would like to ask if there is some part of my code that I could improve or something else I could check since the response doesn't give me any leads.

UPDATE #1

Here are the formats of the const variables:

  • REFRESH_TOKEN: Atzr|[a-zA-Z0-9-]*
  • CLIENT_ID: amzn1.application-oa2-client.[a-z0-9]{32}
  • CLIENT_SECRET: [a-z0-9]{64}

In the sample code provided by Amazon they do a POST to this address:

POST /auth/o2/token HTTP/l.l

However I'm not including HTTP/l.l on my base_url. I'm not sure if that would play a role in this problem.

UPDATE #2

I could generate an access token using the following curl command on my cmd terminal (Windows user) following this example:

curl -k -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=refresh_token&refresh_token=Atzr|IwE....&client_id=amzn1.application-oa2-client.d67...&client_secret=317dcd..." https://api.amazon.com/auth/O2/token

The response that I got was:

{"access_token":"Atza|IwEB...","token_type":"bearer","expires_in":3600}

As Tanaike points out its very likely that Google Apps Script might not be able to request to the endpoint.



Solution 1:[1]

Modification points:

  • The default content type of UrlFetchApp.fetch is application/x-www-form-urlencoded. And, UTF-8 is used.
  • I'm not sure whether the special characters are included in the values of REFRESH_TOKEN, CLIENT_ID and CLIENT_SECRET. So, how about reflecting the URL encode?

When above points are reflected to your script, it becomes as follows.

Modified script:

var base_url = 'https://api.amazon.com/auth/o2/token';
var pointParams = "?grant_type=refresh_token&refresh_token=" + encodeURIComponent(REFRESH_TOKEN) + "&client_id=" + encodeURIComponent(CLIENT_ID) + "&client_secret=" + encodeURIComponent(CLIENT_SECRET);
var query_string = base_url + pointParams;
var options = {
  'method' : 'POST',
  //'muteHttpExceptions': true
};

Note:

  • Please confirm whether your values of REFRESH_TOKEN, CLIENT_ID and CLIENT_SECRET are the valid values again.
  • By the way, your question says For that we would need the following inputs:grant_type (parameter) refresh_token (input) scope (parameter) client_id (input) client_secret (input). But, it seems that your script doesn't include scope.

Added:

From your updated question, when your following curl command works fine,

curl -k -X POST -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=refresh_token&refresh_token=Atzr|IwE....&client_id=amzn1.application-oa2-client.d67...&client_secret=317dcd..." https://api.amazon.com/auth/O2/token

The Google Apps Script is required to be modified. Because your curl command sends the data as the form data. So could you please test the following sample script?

Sample script:

Please set the variables and test it.

var base_url = 'https://api.amazon.com/auth/O2/token';
var options = {
  method: "post",
  payload: {
    grant_type: "refresh_token",
    refresh_token: REFRESH_TOKEN,
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET
  },
  // muteHttpExceptions: true
};
var rawData = UrlFetchApp.fetch(base_url, options).getContentText();
Logger.log(rawData)

Solution 2:[2]

Content-type "application/x-www-form-urlencoded" is not working. Changed it for "application/json" and it works:

function AccessToken() {
  var url = "https://api.amazon.com/auth/o2/token"
  var params= {
    "method":"POST",
    headers: {
      "Content-Type":"application/json"
    },
    payload: JSON.stringify({
      "client_id":CLIENT_ID,
      "client_secret":CLIENT_SECRET,
      "grant_type":"refresh_token",
      "refresh_token":REFRESH_TOKEN
      //"scope":"appstore::apps:readwrite"
    })
  };
  var response = JSON.parse(UrlFetchApp.fetch(url, params).getContentText());
  Logger.log(response)
  return response.access_token
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2