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 2025-08-20 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 2025-08-20 UTC."],[[["\u003cp\u003eEnables sending signed OAuth1.0 requests to API resources using consumer and access tokens.\u003c/p\u003e\n"],["\u003cp\u003eProvides a \u003ccode\u003efetch\u003c/code\u003e method to make authenticated requests with specified URL, parameters, and options.\u003c/p\u003e\n"],["\u003cp\u003eHandles OAuth1.0 signature generation, nonce creation, and Authorization header construction.\u003c/p\u003e\n"],["\u003cp\u003eAllows for both GET and POST requests with optional payload data.\u003c/p\u003e\n"],["\u003cp\u003eOffers utility functions for URL parameter encoding, form data escaping, and request string generation.\u003c/p\u003e\n"]]],[],null,["# OAuth1.0 library\n\nSend signed OAuth1.0 requests\n-----------------------------\n\n```gdscript\n/**\n * Adds a OAuth1 object to the global scope. This can be used as follows:\n *\n * const urlFetch = OAuth1.withAccessToken(consumerKey, consumerSecret,\n * accessToken, accessSecret);\n * const response = urlFetch.fetch(url, params, options);\n */\n(function(scope) {\n /**\n * Creates an object to provide OAuth1-based requests to API resources.\n * @param {string} consumerKey\n * @param {string} consumerSecret\n * @param {string} accessToken\n * @param {string} accessSecret\n * @constructor\n */\n function OAuth1UrlFetchApp(\n consumerKey, consumerSecret, accessToken, accessSecret) {\n this.consumerKey_ = consumerKey;\n this.consumerSecret_ = consumerSecret;\n this.accessToken_ = accessToken;\n this.accessSecret_ = accessSecret;\n }\n\n /**\n * Sends a signed OAuth 1.0 request.\n * @param {string} url The URL of the API resource.\n * @param {?Object.\u003cstring\u003e=} opt_params Map of parameters for the URL.\n * @param {?Object.\u003cstring\u003e=} opt_options Options for passing to UrlFetchApp\n * for example, to set the method to POST, or to include a form body.\n * @return {?Object} The resulting object on success, or null if a failure.\n */\n OAuth1UrlFetchApp.prototype.fetch = function(url, opt_params, opt_options) {\n const oauthParams = {\n 'oauth_consumer_key': this.consumerKey_,\n 'oauth_timestamp': parseInt(new Date().getTime() / 1000),\n 'oauth_nonce': this.generateNonce_(),\n 'oauth_version': '1.0',\n 'oauth_token': this.accessToken_,\n 'oauth_signature_method': 'HMAC-SHA1'\n };\n\n const method = 'GET';\n if (opt_options && opt_options.method) {\n method = opt_options.method;\n }\n if (opt_options && opt_options.payload) {\n const formPayload = opt_options.payload;\n }\n\n const requestString =\n this.generateRequestString_(oauthParams, opt_params, formPayload);\n const signatureBaseString =\n this.generateSignatureBaseString_(method, url, requestString);\n const signature = Utilities.computeHmacSignature(\n Utilities.MacAlgorithm.HMAC_SHA_1, signatureBaseString,\n this.getSigningKey_());\n const b64signature = Utilities.base64Encode(signature);\n\n oauthParams['oauth_signature'] = this.escape_(b64signature);\n const fetchOptions = opt_options || {};\n fetchOptions['headers'] = {\n Authorization: this.generateAuthorizationHeader_(oauthParams)\n };\n if (fetchOptions.payload) {\n fetchOptions.payload = this.escapeForm_(fetchOptions.payload);\n }\n return UrlFetchApp.fetch(\n this.joinUrlToParams_(url, opt_params), fetchOptions);\n };\n\n /**\n * Concatenates request URL to parameters to form a single string.\n * @param {string} url The URL of the resource.\n * @param {?Object.\u003cstring\u003e=} opt_params Optional key/value map of parameters.\n * @return {string} The full path built out with parameters.\n */\n OAuth1UrlFetchApp.prototype.joinUrlToParams_ = function(url, opt_params) {\n if (!opt_params) {\n return url;\n }\n const paramKeys = Object.keys(opt_params);\n const paramList = [];\n for (const key in opt_params) {\n paramList.push(`${key}=${opt_params[key]}`);\n }\n return `${url}?${paramList.join('&')}`;\n };\n\n /**\n * Generates a random nonce for use in the OAuth request.\n * @return {string} A random string.\n */\n OAuth1UrlFetchApp.prototype.generateNonce_ = function() {\n return Utilities\n .base64Encode(Utilities.computeDigest(\n Utilities.DigestAlgorithm.SHA_1,\n parseInt(Math.floor(Math.random() * 10000))))\n .replace(/[\\/=_+]/g, '');\n };\n\n /**\n * Creates a properly-formatted string from a map of key/values from a form\n * post.\n * @param {!Object.\u003cstring\u003e} payload Map of key/values.\n * @return {string} The formatted string for the body of the POST message.\n */\n OAuth1UrlFetchApp.prototype.escapeForm_ = function(payload) {\n const escaped = [];\n for (const key in payload) {\n escaped.push(`${this.escape_(key)}=${this.escape_(payload[key])}`);\n }\n return escaped.join('&');\n };\n\n /**\n * Returns a percent-escaped string for use with OAuth. Note that\n * encodeURIComponent is not sufficient for this as the Twitter API expects\n * characters such as exclamation-mark to be encoded. See:\n * https://dev.twitter.com/discussions/12378\n * @param {string} str The string to be escaped.\n * @return {string} The escaped string.\n */\n OAuth1UrlFetchApp.prototype.escape_ = function(str) {\n return encodeURIComponent(str).replace(/[!*()']/g, function(v) {\n return '%' + v.charCodeAt().toString(16);\n });\n };\n\n /**\n * Generates the Authorization header using the OAuth parameters and\n * calculated signature.\n * @param {!Object} oauthParams A map of the required OAuth parameters. See:\n * https://dev.twitter.com/oauth/overview/authorizing-requests\n * @return {string} An Authorization header value for use in HTTP requests.\n */\n OAuth1UrlFetchApp.prototype.generateAuthorizationHeader_ = function(\n oauthParams) {\n const params = [];\n for (const key in oauthParams) {\n params.push(`${key}=\"${oauthParams[key]}\"`);\n }\n return `OAuth ${params.join(', ')}`;\n };\n\n /**\n * Generates the signature string for the request.\n * @param {string} method The HTTP method e.g. GET, POST\n * @param {string} The URL.\n * @param {string} requestString The string representing the parameters to the\n * API call as constructed by generateRequestString.\n * @return {string} The signature base string. See:\n * https://dev.twitter.com/oauth/overview/creating-signatures\n */\n OAuth1UrlFetchApp.prototype.generateSignatureBaseString_ = function(\n method, url, requestString) {\n return [method, this.escape_(url), this.escape_(requestString)].join('&');\n };\n\n /**\n * Generates the key for signing the OAuth request\n * @return {string} The signing key.\n */\n OAuth1UrlFetchApp.prototype.getSigningKey_ = function() {\n return this.escape_(this.consumerSecret_) + '&' +\n this.escape_(this.accessSecret_);\n };\n\n /**\n * Generates the request string for signing, as used to produce a signature\n * for the Authorization header. see:\n * https://dev.twitter.com/oauth/overview/creating-signatures\n * @param {!Object} oauthParams The required OAuth parameters for the request,\n * see: https://dev.twitter.com/oauth/overview/authorizing-requests\n * @param {?Object=} opt_params Optional parameters specified as part of the\n * request, in map form, for example to specify /path?a=b&c=d&e=f... etc\n * @param {?Object=} opt_formPayload Optional mapping of pairs used in a form\n * as part of a POST request.\n * @return {string} The request string\n */\n OAuth1UrlFetchApp.prototype.generateRequestString_ = function(\n oauthParams, opt_params, opt_formPayload) {\n const requestParams = {};\n const requestPath = [];\n for (let i = 0; i \u003c arguments.length; i++) {\n const mapping = arguments[i];\n if (mapping) {\n const paramKeys = Object.keys(mapping);\n for (let j = 0, paramKey; paramKey = paramKeys[j]; j++) {\n requestParams[paramKey] = mapping[paramKey];\n }\n }\n }\n for (const key in requestParams) {\n requestPath.push(`${this.escape_(key)}=${this.escape_(requestParams[key])}`);\n }\n return requestPath.join('&');\n };\n\n /**\n * Builds a OAuth1UrlFetchApp object based on supplied access token (and other\n * parameters.\n * @param {string} consumerKey\n * @param {string} consumerSecret\n * @param {string} accessToken\n * @param {string} accessSecret\n * @return {!OAuth1UrlFetchApp}\n */\n function withAccessToken(\n consumerKey, consumerSecret, accessToken, accessSecret) {\n return new OAuth1UrlFetchApp(\n consumerKey, consumerSecret, accessToken, accessSecret);\n }\n\n scope.OAuth1 = {withAccessToken: withAccessToken};\n})(this);\n```"]]