From 4eda44f132bc1623fb4dc44ac13fe85dc57908c9 Mon Sep 17 00:00:00 2001 From: Eric Koleda Date: Mon, 3 Dec 2018 09:41:49 -0500 Subject: [PATCH 1/5] Allow for arbitrary redirect URIs. --- src/OAuth2.js | 8 +++++--- src/Service.js | 40 +++++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/OAuth2.js b/src/OAuth2.js index b121b19d..256e9eb8 100644 --- a/src/OAuth2.js +++ b/src/OAuth2.js @@ -59,11 +59,13 @@ function createService(serviceName) { /** * Returns the redirect URI that will be used for a given script. Often this URI * needs to be entered into a configuration screen of your OAuth provider. - * @param {string} scriptId The script ID of your script, which can be found in - * the Script Editor UI under "File > Project properties". + * @param {string} [optScriptId] The script ID of your script, which can be found + * in the Script Editor UI under "File > Project properties". Defaults to + * the script ID of the script being executed. * @return {string} The redirect URI. */ -function getRedirectUri(scriptId) { +function getRedirectUri(optScriptId) { + var scriptId = optScriptId || eval('Script' + 'App').getScriptId(); return 'https://script.google.com/macros/d/' + encodeURIComponent(scriptId) + '/usercallback'; } diff --git a/src/Service.js b/src/Service.js index 045bdb3e..f52712f2 100644 --- a/src/Service.js +++ b/src/Service.js @@ -33,7 +33,6 @@ var Service_ = function(serviceName) { this.params_ = {}; this.tokenFormat_ = TOKEN_FORMAT.JSON; this.tokenHeaders_ = null; - this.scriptId_ = eval('Script' + 'App').getScriptId(); this.expirationMinutes_ = 60; }; @@ -301,6 +300,27 @@ Service_.prototype.setGrantType = function(grantType) { return this; }; +/** + * Sets the URI to redirect to when the OAuth flow has completed. By default the library + * will provide this value automatically, but in some rare cases you may need to + * override it. + * @param {string} redirectURI The redirect URI. + * @return {Service_} This service, for chaining. + */ +Service_.prototype.setRedirectUri = function(redirectUri) { + this.redirectUri_ = redirectUri; + return this; +}; + +/** + * Returns the redirect URI that will be used for this service. Often this URI + * needs to be entered into a configuration screen of your OAuth provider. + * @return {string} The redirect URI. + */ +Service_.prototype.getRedirectUri = function() { + return this.redirectUri_ || getRedirectUri(); +}; + /** * Gets the authorization URL. The first step in getting an OAuth2 token is to * have the user visit this URL and approve the authorization request. The @@ -313,12 +333,10 @@ Service_.prototype.setGrantType = function(grantType) { Service_.prototype.getAuthorizationUrl = function(optAdditionalParameters) { validate_({ 'Client ID': this.clientId_, - 'Script ID': this.scriptId_, 'Callback function name': this.callbackFunctionName_, 'Authorization base URL': this.authorizationBaseUrl_ }); - var redirectUri = getRedirectUri(this.scriptId_); var stateTokenBuilder = eval('Script' + 'App').newStateToken() .withMethod(this.callbackFunctionName_) .withArgument('serviceName', this.serviceName_) @@ -331,7 +349,7 @@ Service_.prototype.getAuthorizationUrl = function(optAdditionalParameters) { var params = { client_id: this.clientId_, response_type: 'code', - redirect_uri: redirectUri, + redirect_uri: this.getRedirectUri(), state: stateTokenBuilder.createToken() }; params = extend_(params, this.params_); @@ -358,15 +376,13 @@ Service_.prototype.handleCallback = function(callbackRequest) { validate_({ 'Client ID': this.clientId_, 'Client Secret': this.clientSecret_, - 'Script ID': this.scriptId_, 'Token URL': this.tokenUrl_ }); - var redirectUri = getRedirectUri(this.scriptId_); var payload = { code: code, client_id: this.clientId_, client_secret: this.clientSecret_, - redirect_uri: redirectUri, + redirect_uri: this.getRedirectUri(), grant_type: 'authorization_code' }; var token = this.fetchToken_(payload); @@ -447,16 +463,6 @@ Service_.prototype.getLastError = function() { return this.lastError_; }; -/** - * Returns the redirect URI that will be used for this service. Often this URI - * needs to be entered into a configuration screen of your OAuth provider. - * @return {string} The redirect URI. - */ -Service_.prototype.getRedirectUri = function() { - return getRedirectUri(this.scriptId_); -}; - - /** * Fetches a new token from the OAuth server. * @param {Object} payload The token request payload. From c2562a8767d9cbd33ce95f4c2e1e2ff884ea87ba Mon Sep 17 00:00:00 2001 From: Eric Koleda Date: Mon, 3 Dec 2018 09:55:16 -0500 Subject: [PATCH 2/5] Add eBay sample. --- samples/eBay.gs | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 samples/eBay.gs diff --git a/samples/eBay.gs b/samples/eBay.gs new file mode 100644 index 00000000..805d3fc9 --- /dev/null +++ b/samples/eBay.gs @@ -0,0 +1,92 @@ +/* + * This sample demonstrates how to configure the library for the eBay API, + * using the authorization code flow to get a user access token. + * Instructions on how to generate OAuth credentuals is available here: + * https://developer.ebay.com/api-docs/static/oauth-qref-auth-code-grant.html + */ + +var CLIENT_ID = '...'; // App ID +var CLIENT_SECRET = '...'; // Cert ID +var RU_NAME = '...' // eBay Redirect URL name. + +/** + * Authorizes and makes a request to the Ebay API. + */ +function run() { + var service = getService(); + if (service.hasAccess()) { + // Sandbox environment. + var url = 'https://api.sandbox.ebay.com/sell/inventory/v1/inventory_item'; + var response = UrlFetchApp.fetch(url, { + headers: { + Authorization: 'Bearer ' + service.getAccessToken() + } + }); + var result = JSON.parse(response.getContentText()); + Logger.log(JSON.stringify(result, null, 2)); + } else { + var authorizationUrl = service.getAuthorizationUrl(); + Logger.log('Open the following URL and re-run the script: %s', + authorizationUrl); + } +} + +/** + * Reset the authorization state, so that it can be re-tested. + */ +function reset() { + getService().reset(); +} + +/** + * Configures the service. + */ +function getService() { + return OAuth2.createService('eBay') + // Set the endpoint URLs (sandbox environment). + .setTokenUrl('https://api.sandbox.ebay.com/identity/v1/oauth2/token') + .setAuthorizationBaseUrl('https://signin.sandbox.ebay.com/authorize') + + // Set the client ID and secret. + .setClientId(CLIENT_ID) + .setClientSecret(CLIENT_SECRET) + + // Set the name of the callback function in the script referenced + // above that should be invoked to complete the OAuth flow. + .setCallbackFunction('authCallback') + + // Set the property store where authorized tokens should be persisted. + .setPropertyStore(PropertiesService.getUserProperties()) + + // Set the redirect URI to the RuName (eBay Redirect URL name). + .setRedirectUri(RU_NAME) + + // Set the require scopes. + .setScope('https://api.ebay.com/oauth/api_scope/sell.inventory.readonly') + + // Add a Basic Authorization header to token requests. + .setTokenHeaders({ + Authorization: 'Basic ' + + Utilities.base64Encode(CLIENT_ID + ':' + CLIENT_SECRET) + }); +} + +/** + * Handles the OAuth2 callback. + */ +function authCallback(request) { + var service = getService(); + var authorized = service.handleCallback(request); + if (authorized) { + return HtmlService.createHtmlOutput('Success!'); + } else { + return HtmlService.createHtmlOutput('Denied.'); + } +} + +/** + * Logs the redict URI to register. + */ +function logRedirectUri() { + Logger.log(OAuth2.getRedirectUri()); +} From d58ab1319ea1c01193f0b8e1a7ec7c89eb6e810d Mon Sep 17 00:00:00 2001 From: Eric Koleda Date: Mon, 3 Dec 2018 09:56:24 -0500 Subject: [PATCH 3/5] Update the samples to use OAuth2.getRedirectUri() --- samples/Add-on/Code.gs | 3 +-- samples/AdobeSign.gs | 2 +- samples/Basecamp.gs | 2 +- samples/ChatWork.gs | 2 +- samples/CloudIdentityAwareProxy.gs | 2 +- samples/Dropbox.gs | 2 +- samples/Facebook.gs | 2 +- samples/FitBit.gs | 2 +- samples/GitHub.gs | 2 +- samples/GooglePlus.gs | 2 +- samples/Harvest.gs | 2 +- samples/Jira.gs | 2 +- samples/LinkedIn.gs | 2 +- samples/Medium.gs | 2 +- samples/Meetup.gs | 2 +- samples/RingCentral.gs | 2 +- samples/Salesforce.gs | 2 +- samples/Smartsheet.gs | 2 +- samples/Strava.gs | 2 +- samples/UltraCart.gs | 2 +- samples/VK.gs | 2 +- samples/WebApp/Code.gs | 3 +-- samples/Wordpress.gs | 2 +- samples/Yahoo.gs | 2 +- samples/Yandex.gs | 2 +- samples/Zendesk.gs | 2 +- samples/Zoom.gs | 2 +- 27 files changed, 27 insertions(+), 29 deletions(-) diff --git a/samples/Add-on/Code.gs b/samples/Add-on/Code.gs index 7b2e3efd..4a2e297f 100644 --- a/samples/Add-on/Code.gs +++ b/samples/Add-on/Code.gs @@ -160,8 +160,7 @@ function authCallback(request) { * Logs the redict URI to register in the Google Developers Console. */ function logRedirectUri() { - var service = getGitHubService(); - Logger.log(service.getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } /** diff --git a/samples/AdobeSign.gs b/samples/AdobeSign.gs index 4d446c9c..d2ff57e3 100644 --- a/samples/AdobeSign.gs +++ b/samples/AdobeSign.gs @@ -97,5 +97,5 @@ function authCallback(request) { * Logs the redict URI to register in the Dropbox application settings. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Basecamp.gs b/samples/Basecamp.gs index b995310d..96fa8617 100644 --- a/samples/Basecamp.gs +++ b/samples/Basecamp.gs @@ -69,5 +69,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/ChatWork.gs b/samples/ChatWork.gs index d8eecf8d..c2cc0ea4 100644 --- a/samples/ChatWork.gs +++ b/samples/ChatWork.gs @@ -81,5 +81,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/CloudIdentityAwareProxy.gs b/samples/CloudIdentityAwareProxy.gs index 8aba606b..2185041b 100644 --- a/samples/CloudIdentityAwareProxy.gs +++ b/samples/CloudIdentityAwareProxy.gs @@ -98,5 +98,5 @@ function authCallback(request) { * Logs the redict URI to register in the Google Developers Console. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Dropbox.gs b/samples/Dropbox.gs index 3e6c4c4e..b6fa7509 100644 --- a/samples/Dropbox.gs +++ b/samples/Dropbox.gs @@ -74,5 +74,5 @@ function authCallback(request) { * Logs the redict URI to register in the Dropbox application settings. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Facebook.gs b/samples/Facebook.gs index 11b1c7b2..01c9efb8 100644 --- a/samples/Facebook.gs +++ b/samples/Facebook.gs @@ -73,5 +73,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/FitBit.gs b/samples/FitBit.gs index 748aa2b9..1275c31b 100644 --- a/samples/FitBit.gs +++ b/samples/FitBit.gs @@ -74,5 +74,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/GitHub.gs b/samples/GitHub.gs index bb795880..3f017fd5 100644 --- a/samples/GitHub.gs +++ b/samples/GitHub.gs @@ -67,5 +67,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/GooglePlus.gs b/samples/GooglePlus.gs index de6e1dba..6b0ec0fc 100644 --- a/samples/GooglePlus.gs +++ b/samples/GooglePlus.gs @@ -73,6 +73,6 @@ function authCallback(request) { * Logs the redict URI to register in the Google Developers Console. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Harvest.gs b/samples/Harvest.gs index d126a3e2..7abab4c5 100644 --- a/samples/Harvest.gs +++ b/samples/Harvest.gs @@ -79,5 +79,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Jira.gs b/samples/Jira.gs index 9fe436dc..10d38699 100644 --- a/samples/Jira.gs +++ b/samples/Jira.gs @@ -109,5 +109,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/LinkedIn.gs b/samples/LinkedIn.gs index c96aaa10..29c629a3 100644 --- a/samples/LinkedIn.gs +++ b/samples/LinkedIn.gs @@ -68,5 +68,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Medium.gs b/samples/Medium.gs index b074bf7a..c9cf43a6 100644 --- a/samples/Medium.gs +++ b/samples/Medium.gs @@ -75,5 +75,5 @@ function authCallback_(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Meetup.gs b/samples/Meetup.gs index 20183667..652a814f 100644 --- a/samples/Meetup.gs +++ b/samples/Meetup.gs @@ -73,5 +73,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/RingCentral.gs b/samples/RingCentral.gs index 4d5cb6c4..23eec69e 100644 --- a/samples/RingCentral.gs +++ b/samples/RingCentral.gs @@ -82,5 +82,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Salesforce.gs b/samples/Salesforce.gs index fc2edf33..e6dfed4c 100644 --- a/samples/Salesforce.gs +++ b/samples/Salesforce.gs @@ -105,5 +105,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Smartsheet.gs b/samples/Smartsheet.gs index c177f2c8..2a9134cb 100644 --- a/samples/Smartsheet.gs +++ b/samples/Smartsheet.gs @@ -105,5 +105,5 @@ function smartsheetTokenHandler(payload) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Strava.gs b/samples/Strava.gs index 08879f66..4cad09b7 100644 --- a/samples/Strava.gs +++ b/samples/Strava.gs @@ -72,5 +72,5 @@ function authCallback_(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/UltraCart.gs b/samples/UltraCart.gs index 71425b8f..b7a47cf9 100644 --- a/samples/UltraCart.gs +++ b/samples/UltraCart.gs @@ -73,5 +73,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/VK.gs b/samples/VK.gs index 4febfe28..79b5a82e 100644 --- a/samples/VK.gs +++ b/samples/VK.gs @@ -73,5 +73,5 @@ function authCallback(request) { * Logs the redict URI to register in the VK Aps Page https://vk.com/apps?act=manage. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/WebApp/Code.gs b/samples/WebApp/Code.gs index 422894b7..0677fbc6 100644 --- a/samples/WebApp/Code.gs +++ b/samples/WebApp/Code.gs @@ -133,8 +133,7 @@ function authCallback(request) { * Logs the redict URI to register in the Google Developers Console. */ function logRedirectUri() { - var service = getGitHubService(); - Logger.log(service.getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } /** diff --git a/samples/Wordpress.gs b/samples/Wordpress.gs index d8143712..309039e6 100644 --- a/samples/Wordpress.gs +++ b/samples/Wordpress.gs @@ -68,5 +68,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Yahoo.gs b/samples/Yahoo.gs index 746a06a8..6bea7ab4 100644 --- a/samples/Yahoo.gs +++ b/samples/Yahoo.gs @@ -73,5 +73,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Yandex.gs b/samples/Yandex.gs index 1502e681..6c2a3823 100644 --- a/samples/Yandex.gs +++ b/samples/Yandex.gs @@ -72,5 +72,5 @@ function authCallback(request) { * Logs the redict URI to register in the Yandex oAuth Page https://oauth.yandex.ru/client/new. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Zendesk.gs b/samples/Zendesk.gs index b1a0fd26..ec9a3b8a 100644 --- a/samples/Zendesk.gs +++ b/samples/Zendesk.gs @@ -78,5 +78,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } diff --git a/samples/Zoom.gs b/samples/Zoom.gs index 473a9189..3d0ee067 100644 --- a/samples/Zoom.gs +++ b/samples/Zoom.gs @@ -85,5 +85,5 @@ function authCallback(request) { * Logs the redict URI to register. */ function logRedirectUri() { - Logger.log(getService().getRedirectUri()); + Logger.log(OAuth2.getRedirectUri()); } From c58bcefb9513ae3ff7d14d09cc9019f47143af24 Mon Sep 17 00:00:00 2001 From: Eric Koleda Date: Mon, 3 Dec 2018 09:59:26 -0500 Subject: [PATCH 4/5] Fix lint errors. --- samples/eBay.gs | 2 +- src/OAuth2.js | 6 +++--- src/Service.js | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/samples/eBay.gs b/samples/eBay.gs index 805d3fc9..01cd9cde 100644 --- a/samples/eBay.gs +++ b/samples/eBay.gs @@ -7,7 +7,7 @@ var CLIENT_ID = '...'; // App ID var CLIENT_SECRET = '...'; // Cert ID -var RU_NAME = '...' // eBay Redirect URL name. +var RU_NAME = '...'; // eBay Redirect URL name. /** * Authorizes and makes a request to the Ebay API. diff --git a/src/OAuth2.js b/src/OAuth2.js index 256e9eb8..8c5a002e 100644 --- a/src/OAuth2.js +++ b/src/OAuth2.js @@ -59,9 +59,9 @@ function createService(serviceName) { /** * Returns the redirect URI that will be used for a given script. Often this URI * needs to be entered into a configuration screen of your OAuth provider. - * @param {string} [optScriptId] The script ID of your script, which can be found - * in the Script Editor UI under "File > Project properties". Defaults to - * the script ID of the script being executed. + * @param {string} [optScriptId] The script ID of your script, which can be + * found in the Script Editor UI under "File > Project properties". Defaults + * to the script ID of the script being executed. * @return {string} The redirect URI. */ function getRedirectUri(optScriptId) { diff --git a/src/Service.js b/src/Service.js index f52712f2..90be5b80 100644 --- a/src/Service.js +++ b/src/Service.js @@ -301,10 +301,10 @@ Service_.prototype.setGrantType = function(grantType) { }; /** - * Sets the URI to redirect to when the OAuth flow has completed. By default the library - * will provide this value automatically, but in some rare cases you may need to - * override it. - * @param {string} redirectURI The redirect URI. + * Sets the URI to redirect to when the OAuth flow has completed. By default the + * library will provide this value automatically, but in some rare cases you may + * need to override it. + * @param {string} redirectUri The redirect URI. * @return {Service_} This service, for chaining. */ Service_.prototype.setRedirectUri = function(redirectUri) { From 980e7c1fbfb9382f73d628d6a1d9c57d8504d8e8 Mon Sep 17 00:00:00 2001 From: Eric Koleda Date: Fri, 21 Dec 2018 16:00:34 -0500 Subject: [PATCH 5/5] Remove ScriptApp workaround. --- src/OAuth2.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OAuth2.js b/src/OAuth2.js index 8c5a002e..6dd5ddb1 100644 --- a/src/OAuth2.js +++ b/src/OAuth2.js @@ -65,7 +65,7 @@ function createService(serviceName) { * @return {string} The redirect URI. */ function getRedirectUri(optScriptId) { - var scriptId = optScriptId || eval('Script' + 'App').getScriptId(); + var scriptId = optScriptId || ScriptApp.getScriptId(); return 'https://script.google.com/macros/d/' + encodeURIComponent(scriptId) + '/usercallback'; }