This is the legacy documentation for Google Ads scripts. Go to the current docs.

OAuth1.0 library

Stay organized with collections Save and categorize content based on your preferences.

Send signed OAuth1.0 requests

/**
 * Adds a OAuth1 object to the global scope. This can be used as follows:
 *
 * var urlFetch = OAuth1.withAccessToken(consumerKey, consumerSecret,
 *     accessToken, accessSecret);
 * var response = urlFetch.fetch(url, params, options);
 */
(function(scope) {
  /**
   * Creates an object to provide OAuth1-based requests to API resources.
   * @param {string} consumerKey
   * @param {string} consumerSecret
   * @param {string} accessToken
   * @param {string} accessSecret
   * @constructor
   */
  function OAuth1UrlFetchApp(
      consumerKey, consumerSecret, accessToken, accessSecret) {
    this.consumerKey_ = consumerKey;
    this.consumerSecret_ = consumerSecret;
    this.accessToken_ = accessToken;
    this.accessSecret_ = accessSecret;
  }

  /**
   * Sends a signed OAuth 1.0 request.
   * @param {string} url The URL of the API resource.
   * @param {?Object.<string>=} opt_params Map of parameters for the URL.
   * @param {?Object.<string>=} opt_options Options for passing to UrlFetchApp
   *     for example, to set the method to POST, or to include a form body.
   * @return {?Object} The resulting object on success, or null if a failure.
   */
  OAuth1UrlFetchApp.prototype.fetch = function(url, opt_params, opt_options) {
    var oauthParams = {
      'oauth_consumer_key': this.consumerKey_,
      'oauth_timestamp': parseInt(new Date().getTime() / 1000),
      'oauth_nonce': this.generateNonce_(),
      'oauth_version': '1.0',
      'oauth_token': this.accessToken_,
      'oauth_signature_method': 'HMAC-SHA1'
    };

    var method = 'GET';
    if (opt_options && opt_options.method) {
      method = opt_options.method;
    }
    if (opt_options && opt_options.payload) {
      var formPayload = opt_options.payload;
    }

    var requestString =
        this.generateRequestString_(oauthParams, opt_params, formPayload);
    var signatureBaseString =
        this.generateSignatureBaseString_(method, url, requestString);
    var signature = Utilities.computeHmacSignature(
        Utilities.MacAlgorithm.HMAC_SHA_1, signatureBaseString,
        this.getSigningKey_());
    var b64signature = Utilities.base64Encode(signature);

    oauthParams['oauth_signature'] = this.escape_(b64signature);
    var fetchOptions = opt_options || {};
    fetchOptions['headers'] = {
      Authorization: this.generateAuthorizationHeader_(oauthParams)
    };
    if (fetchOptions.payload) {
      fetchOptions.payload = this.escapeForm_(fetchOptions.payload);
    }
    return UrlFetchApp.fetch(
        this.joinUrlToParams_(url, opt_params), fetchOptions);
  };

  /**
   * Concatenates request URL to parameters to form a single string.
   * @param {string} url The URL of the resource.
   * @param {?Object.<string>=} opt_params Optional key/value map of parameters.
   * @return {string} The full path built out with parameters.
   */
  OAuth1UrlFetchApp.prototype.joinUrlToParams_ = function(url, opt_params) {
    if (!opt_params) {
      return url;
    }
    var paramKeys = Object.keys(opt_params);
    var paramList = [];
    for (var i = 0, paramKey; paramKey = paramKeys[i]; i++) {
      paramList.push([paramKey, opt_params[paramKey]].join('='));
    }
    return url + '?' + paramList.join('&');
  };

  /**
   * Generates a random nonce for use in the OAuth request.
   * @return {string} A random string.
   */
  OAuth1UrlFetchApp.prototype.generateNonce_ = function() {
    return Utilities
        .base64Encode(Utilities.computeDigest(
            Utilities.DigestAlgorithm.SHA_1,
            parseInt(Math.floor(Math.random() * 10000))))
        .replace(/[\/=_+]/g, '');
  };

  /**
   * Creates a properly-formatted string from a map of key/values from a form
   * post.
   * @param {!Object.<string>} payload Map of key/values.
   * @return {string} The formatted string for the body of the POST message.
   */
  OAuth1UrlFetchApp.prototype.escapeForm_ = function(payload) {
    var escaped = [];
    var keys = Object.keys(payload);
    for (var i = 0, key; key = keys[i]; i++) {
      escaped.push([this.escape_(key), this.escape_(payload[key])].join('='));
    }
    return escaped.join('&');
  };

  /**
   * Returns a percent-escaped string for use with OAuth. Note that
   * encodeURIComponent is not sufficient for this as the Twitter API expects
   * characters such as exclamation-mark to be encoded. See:
   *     https://dev.twitter.com/discussions/12378
   * @param {string} str The string to be escaped.
   * @return {string} The escaped string.
   */
  OAuth1UrlFetchApp.prototype.escape_ = function(str) {
    return encodeURIComponent(str).replace(/[!*()']/g, function(v) {
      return '%' + v.charCodeAt().toString(16);
    });
  };

  /**
   * Generates the Authorization header using the OAuth parameters and
   * calculated signature.
   * @param {!Object} oauthParams A map of the required OAuth parameters. See:
   *     https://dev.twitter.com/oauth/overview/authorizing-requests
   * @return {string} An Authorization header value for use in HTTP requests.
   */
  OAuth1UrlFetchApp.prototype.generateAuthorizationHeader_ = function(
      oauthParams) {
    var params = [];
    var keys = Object.keys(oauthParams).sort();
    for (var i = 0, key; key = keys[i]; i++) {
      params.push(key + '="' + oauthParams[key] + '"');
    }
    return 'OAuth ' + params.join(', ');
  };

  /**
   * Generates the signature string for the request.
   * @param {string} method The HTTP method e.g. GET, POST
   * @param {string} The URL.
   * @param {string} requestString The string representing the parameters to the
   *     API call as constructed by generateRequestString.
   * @return {string} The signature base string. See:
   *     https://dev.twitter.com/oauth/overview/creating-signatures
   */
  OAuth1UrlFetchApp.prototype.generateSignatureBaseString_ = function(
      method, url, requestString) {
    return [method, this.escape_(url), this.escape_(requestString)].join('&');
  };

  /**
   * Generates the key for signing the OAuth request
   * @return {string} The signing key.
   */
  OAuth1UrlFetchApp.prototype.getSigningKey_ = function() {
    return this.escape_(this.consumerSecret_) + '&' +
        this.escape_(this.accessSecret_);
  };

  /**
   * Generates the request string for signing, as used to produce a signature
   * for the Authorization header. see:
   * https://dev.twitter.com/oauth/overview/creating-signatures
   * @param {!Object} oauthParams The required OAuth parameters for the request,
   *     see: https://dev.twitter.com/oauth/overview/authorizing-requests
   * @param {?Object=} opt_params Optional parameters specified as part of the
   *     request, in map form, for example to specify /path?a=b&c=d&e=f... etc
   * @param {?Object=} opt_formPayload Optional mapping of pairs used in a form
   *     as part of a POST request.
   * @return {string} The request string
   */
  OAuth1UrlFetchApp.prototype.generateRequestString_ = function(
      oauthParams, opt_params, opt_formPayload) {
    var requestParams = {};
    var requestPath = [];
    for (var i = 0; i < arguments.length; i++) {
      var mapping = arguments[i];
      if (mapping) {
        var paramKeys = Object.keys(mapping);
        for (var j = 0, paramKey; paramKey = paramKeys[j]; j++) {
          requestParams[paramKey] = mapping[paramKey];
        }
      }
    }
    var requestKeys = Object.keys(requestParams);
    requestKeys.sort();

    for (var m = 0, requestKey; requestKey = requestKeys[m]; m++) {
      requestPath.push([
        this.escape_(requestKey), this.escape_(requestParams[requestKey])
      ].join('='));
    }
    return requestPath.join('&');
  };

  /**
   * Builds a OAuth1UrlFetchApp object based on supplied access token (and other
   * parameters.
   * @param {string} consumerKey
   * @param {string} consumerSecret
   * @param {string} accessToken
   * @param {string} accessSecret
   * @return {!OAuth1UrlFetchApp}
   */
  function withAccessToken(
      consumerKey, consumerSecret, accessToken, accessSecret) {
    return new OAuth1UrlFetchApp(
        consumerKey, consumerSecret, accessToken, accessSecret);
  }

  scope.OAuth1 = {withAccessToken: withAccessToken};
})(this);