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:
*
* const urlFetch = OAuth1.withAccessToken(consumerKey, consumerSecret,
* accessToken, accessSecret);
* const 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) {
const 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'
};
const method = 'GET';
if (opt_options && opt_options.method) {
method = opt_options.method;
}
if (opt_options && opt_options.payload) {
const formPayload = opt_options.payload;
}
const requestString =
this.generateRequestString_(oauthParams, opt_params, formPayload);
const signatureBaseString =
this.generateSignatureBaseString_(method, url, requestString);
const signature = Utilities.computeHmacSignature(
Utilities.MacAlgorithm.HMAC_SHA_1, signatureBaseString,
this.getSigningKey_());
const b64signature = Utilities.base64Encode(signature);
oauthParams['oauth_signature'] = this.escape_(b64signature);
const 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;
}
const paramKeys = Object.keys(opt_params);
const paramList = [];
for (const key in opt_params) {
paramList.push(`${key}=${opt_params[key]}`);
}
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) {
const escaped = [];
for (const key in payload) {
escaped.push(`${this.escape_(key)}=${this.escape_(payload[key])}`);
}
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) {
const params = [];
for (const key in oauthParams) {
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) {
const requestParams = {};
const requestPath = [];
for (let i = 0; i < arguments.length; i++) {
const mapping = arguments[i];
if (mapping) {
const paramKeys = Object.keys(mapping);
for (let j = 0, paramKey; paramKey = paramKeys[j]; j++) {
requestParams[paramKey] = mapping[paramKey];
}
}
}
for (const key in requestParams) {
requestPath.push(`${this.escape_(key)}=${this.escape_(requestParams[key])}`);
}
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);
Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.
Last updated 2022-03-14 UTC.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2022-03-14 UTC."],[[["Enables sending signed OAuth1.0 requests to API resources using consumer and access tokens."],["Provides a `fetch` method to make authenticated requests with specified URL, parameters, and options."],["Handles OAuth1.0 signature generation, nonce creation, and Authorization header construction."],["Allows for both GET and POST requests with optional payload data."],["Offers utility functions for URL parameter encoding, form data escaping, and request string generation."]]],[]]