AI-generated Key Takeaways
-
The provided code demonstrates how to create signed OAuth1.0 requests using a custom
OAuth1UrlFetchAppobject. -
The
OAuth1UrlFetchAppobject is initialized with consumer and access tokens and secrets. -
The
fetchmethod of theOAuth1UrlFetchAppis used to send signed requests to API resources. -
The code includes helper functions to generate necessary OAuth1 parameters like nonce, signature base string, signing key, and the Authorization header.
-
The
withAccessTokenfunction provides a way to easily create anOAuth1UrlFetchAppinstance with the required credentials.
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 );

