Skip to content
This repository was archived by the owner on Jun 11, 2025. It is now read-only.

Commit 0673b8a

Browse files
authored
fix: prevent samples from leaking OAuth client ID + Secret to users (#54)
Previously, the getService method was public in most of the samples, letting any user of any sample application execute the method using google.script.run to exfiltrate the OAuth Client ID and Secret from the server. Now, these methods are made private by appending an _ to their names, preventing this issue.
1 parent 28e1355 commit 0673b8a

File tree

14 files changed

+59
-55
lines changed

14 files changed

+59
-55
lines changed

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ exact URL that the service will use when performing the OAuth flow:
5151
* Logs the callback URL to register.
5252
*/
5353
function logCallbackUrl() {
54-
var service = getService();
54+
var service = getService_();
5555
Logger.log(service.getCallbackUrl());
5656
}
5757
```
@@ -68,8 +68,12 @@ information is not persisted to any data store, so you'll need to create this
6868
object each time you want to use it. The example below shows how to create a
6969
service for the Twitter API.
7070

71+
Ensure the method is private (has an underscore at the end of the name) to
72+
prevent clients from being able to call the method to read your client ID and
73+
secret.
74+
7175
```js
72-
function getTwitterService() {
76+
function getTwitterService_() {
7377
// Create a new service with the given name. The name will be used when
7478
// persisting the authorized token, so ensure it is unique within the
7579
// scope of the property store.
@@ -98,7 +102,7 @@ authorization URL.
98102

99103
```js
100104
function showSidebar() {
101-
var twitterService = getTwitterService();
105+
var twitterService = getTwitterService_();
102106
if (!twitterService.hasAccess()) {
103107
var authorizationUrl = twitterService.authorize();
104108
var template = HtmlService.createTemplate(
@@ -122,7 +126,7 @@ to the user.
122126

123127
```js
124128
function authCallback(request) {
125-
var twitterService = getTwitterService();
129+
var twitterService = getTwitterService_();
126130
var isAuthorized = twitterService.handleCallback(request);
127131
if (isAuthorized) {
128132
return HtmlService.createHtmlOutput('Success! You can close this tab.');
@@ -144,7 +148,7 @@ and automatically signs the requests using the OAuth1 token.
144148

145149
```js
146150
function makeRequest() {
147-
var twitterService = getTwitterService();
151+
var twitterService = getTwitterService_();
148152
var response = twitterService.fetch('https://api.twitter.com/1.1/statuses/user_timeline.json');
149153
// ...
150154
}

samples/Etsy.gs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var CONSUMER_SECRET = '...';
1212
* Authorizes and makes a request to the Etsy API.
1313
*/
1414
function run() {
15-
var service = getService();
15+
var service = getService_();
1616
if (service.hasAccess()) {
1717
var url = 'https://openapi.etsy.com/v2/users/__SELF__/profile';
1818
var response = service.fetch(url);
@@ -32,14 +32,14 @@ function run() {
3232
* Reset the authorization state, so that it can be re-tested.
3333
*/
3434
function reset() {
35-
var service = getService();
35+
var service = getService_();
3636
service.reset();
3737
}
3838

3939
/**
4040
* Configures the service.
4141
*/
42-
function getService() {
42+
function getService_() {
4343
var service = OAuth1.createService('Etsy')
4444
// Set the endpoint URLs.
4545
// Pass the desired scopes in the request token URL.
@@ -62,7 +62,7 @@ function getService() {
6262

6363
// Override the callback URL method to use the web app URL instead.
6464
service.getCallbackUrl = function() {
65-
return ScriptApp.getService().getUrl();
65+
return ScriptApp.getService_().getUrl();
6666
};
6767

6868
return service;
@@ -74,7 +74,7 @@ function getService() {
7474
function doGet(request) {
7575
// Determine if the request is part of an OAuth callback.
7676
if (request.parameter.oauth_token) {
77-
var service = getService();
77+
var service = getService_();
7878
var authorized = service.handleCallback(request);
7979
if (authorized) {
8080
return HtmlService.createHtmlOutput('Success!');

samples/Goodreads.gs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var CONSUMER_SECRET = '...';
1212
* Authorizes and makes a request to the Goodreads API.
1313
*/
1414
function run() {
15-
var service = getService();
15+
var service = getService_();
1616
if (service.hasAccess()) {
1717
var url = 'https://www.goodreads.com/api/auth_user';
1818
var response = service.fetch(url);
@@ -29,14 +29,14 @@ function run() {
2929
* Reset the authorization state, so that it can be re-tested.
3030
*/
3131
function reset() {
32-
var service = getService();
32+
var service = getService_();
3333
service.reset();
3434
}
3535

3636
/**
3737
* Configures the service.
3838
*/
39-
function getService() {
39+
function getService_() {
4040
var service = OAuth1.createService('Goodreads')
4141
// Set the endpoint URLs.
4242
.setAccessTokenUrl('https://www.goodreads.com/oauth/access_token')
@@ -59,7 +59,7 @@ function getService() {
5959

6060
// Override the callback URL method to use the web app URL instead.
6161
service.getCallbackUrl = function() {
62-
return ScriptApp.getService().getUrl();
62+
return ScriptApp.getService_().getUrl();
6363
};
6464

6565
return service;
@@ -71,7 +71,7 @@ function getService() {
7171
function doGet(request) {
7272
// Determine if the request is part of an OAuth callback.
7373
if (request.parameter.oauth_token) {
74-
var service = getService();
74+
var service = getService_();
7575
var authorized = service.handleCallback(request);
7676
if (authorized) {
7777
return HtmlService.createHtmlOutput('Success!');

samples/Jira.gs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n
1212
* Authorizes and makes a request to the Xero API.
1313
*/
1414
function run() {
15-
var service = getService();
15+
var service = getService_();
1616
if (service.hasAccess()) {
1717
var url = SITE + '/rest/api/3/myself';
1818
var response = service.fetch(url, {
@@ -33,13 +33,13 @@ function run() {
3333
* Reset the authorization state, so that it can be re-tested.
3434
*/
3535
function reset() {
36-
getService().reset();
36+
getService_().reset();
3737
}
3838

3939
/**
4040
* Configures the service.
4141
*/
42-
function getService() {
42+
function getService_() {
4343
return OAuth1.createService('Jira')
4444
// Set the endpoint URLs.
4545
.setRequestTokenUrl(SITE + '/plugins/servlet/oauth/request-token')
@@ -68,7 +68,7 @@ function getService() {
6868
* Handles the OAuth callback.
6969
*/
7070
function authCallback(request) {
71-
var service = getService();
71+
var service = getService_();
7272
var authorized = service.handleCallback(request);
7373
if (authorized) {
7474
return HtmlService.createHtmlOutput('Success!');

samples/KhanAcademy.gs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var CONSUMER_SECRET = '...';
55
* Authorizes and makes a request to the TripIt API.
66
*/
77
function run() {
8-
var service = getService();
8+
var service = getService_();
99
if (service.hasAccess()) {
1010
var url = 'https://api.khanacademy.org/api/v1/user';
1111
var response = service.fetch(url);
@@ -22,14 +22,14 @@ function run() {
2222
* Reset the authorization state, so that it can be re-tested.
2323
*/
2424
function reset() {
25-
var service = getService();
25+
var service = getService_();
2626
service.reset();
2727
}
2828

2929
/**
3030
* Configures the service.
3131
*/
32-
function getService() {
32+
function getService_() {
3333
return OAuth1.createService('TripIt')
3434
// Set the endpoint URLs.
3535
.setRequestTokenUrl('https://www.khanacademy.org/api/auth2/request_token')
@@ -55,7 +55,7 @@ function getService() {
5555
* Handles the OAuth2 callback.
5656
*/
5757
function authCallback(request) {
58-
var service = getService();
58+
var service = getService_();
5959
var authorized = service.handleCallback(request);
6060
if (authorized) {
6161
return HtmlService.createHtmlOutput('Success!');

samples/QuickBooks.gs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ var CONSUMER_SECRET = '...';
66
* sandbox company.
77
*/
88
function run() {
9-
var service = getService();
9+
var service = getService_();
1010
if (service.hasAccess()) {
1111
var companyId = PropertiesService.getUserProperties()
1212
.getProperty('QuickBooks.companyId');
@@ -30,14 +30,14 @@ function run() {
3030
* Reset the authorization state, so that it can be re-tested.
3131
*/
3232
function reset() {
33-
var service = getService();
33+
var service = getService_();
3434
service.reset();
3535
}
3636

3737
/**
3838
* Configures the service.
3939
*/
40-
function getService() {
40+
function getService_() {
4141
return OAuth1.createService('QuickBooks')
4242
// Set the endpoint URLs.
4343
.setAccessTokenUrl('https://oauth.intuit.com/oauth/v1/get_access_token')
@@ -60,7 +60,7 @@ function getService() {
6060
* Handles the OAuth callback.
6161
*/
6262
function authCallback(request) {
63-
var service = getService();
63+
var service = getService_();
6464
var authorized = service.handleCallback(request);
6565
if (authorized) {
6666
PropertiesService.getUserProperties()

samples/Semantics3.gs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var API_SECRET = '...';
55
* Authorizes and makes a request to the Semantics3 API.
66
*/
77
function run() {
8-
var service = getService();
8+
var service = getService_();
99
var query = encodeURIComponent(JSON.stringify({
1010
search: 'iPhone'
1111
}));
@@ -18,7 +18,7 @@ function run() {
1818
/**
1919
* Configures the service.
2020
*/
21-
function getService() {
21+
function getService_() {
2222
return OAuth1.createService('Semantics3')
2323
// Set the consumer key and secret.
2424
.setConsumerKey(API_KEY)

samples/Trello.gs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var CONSUMER_SECRET = '...';
55
* Authorizes and makes a request to the Trello API.
66
*/
77
function run() {
8-
var service = getService();
8+
var service = getService_();
99
if (service.hasAccess()) {
1010
var url = 'https://api.trello.com/1/members/me/boards';
1111
var response = service.fetch(url);
@@ -22,14 +22,14 @@ function run() {
2222
* Reset the authorization state, so that it can be re-tested.
2323
*/
2424
function reset() {
25-
var service = getService();
25+
var service = getService_();
2626
service.reset();
2727
}
2828

2929
/**
3030
* Configures the service.
3131
*/
32-
function getService() {
32+
function getService_() {
3333
return OAuth1.createService('Trello')
3434
// Set the endpoint URLs.
3535
.setRequestTokenUrl('https://trello.com/1/OAuthGetRequestToken')
@@ -52,7 +52,7 @@ function getService() {
5252
* Handles the OAuth2 callback.
5353
*/
5454
function authCallback(request) {
55-
var service = getService();
55+
var service = getService_();
5656
var authorized = service.handleCallback(request);
5757
if (authorized) {
5858
return HtmlService.createHtmlOutput('Success!');

samples/TripIt.gs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var CONSUMER_SECRET = '...';
55
* Authorizes and makes a request to the TripIt API.
66
*/
77
function run() {
8-
var service = getService();
8+
var service = getService_();
99
if (service.hasAccess()) {
1010
var url = 'https://api.tripit.com/v1/get/profile?format=json';
1111
var response = service.fetch(url);
@@ -22,14 +22,14 @@ function run() {
2222
* Reset the authorization state, so that it can be re-tested.
2323
*/
2424
function reset() {
25-
var service = getService();
25+
var service = getService_();
2626
service.reset();
2727
}
2828

2929
/**
3030
* Configures the service.
3131
*/
32-
function getService() {
32+
function getService_() {
3333
return OAuth1.createService('TripIt')
3434
// Set the endpoint URLs.
3535
.setRequestTokenUrl('https://api.tripit.com/oauth/request_token')
@@ -55,7 +55,7 @@ function getService() {
5555
* Handles the OAuth callback.
5656
*/
5757
function authCallback(request) {
58-
var service = getService();
58+
var service = getService_();
5959
var authorized = service.handleCallback(request);
6060
if (authorized) {
6161
return HtmlService.createHtmlOutput('Success!');

samples/Twitter.gs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var CONSUMER_SECRET = '...';
55
* Authorizes and makes a request to the Twitter API.
66
*/
77
function run() {
8-
var service = getService();
8+
var service = getService_();
99
if (service.hasAccess()) {
1010
var url = 'https://api.twitter.com/1.1/statuses/update.json';
1111
var payload = {
@@ -28,14 +28,14 @@ function run() {
2828
* Reset the authorization state, so that it can be re-tested.
2929
*/
3030
function reset() {
31-
var service = getService();
31+
var service = getService_();
3232
service.reset();
3333
}
3434

3535
/**
3636
* Configures the service.
3737
*/
38-
function getService() {
38+
function getService_() {
3939
return OAuth1.createService('Twitter')
4040
// Set the endpoint URLs.
4141
.setAccessTokenUrl('https://api.twitter.com/oauth/access_token')
@@ -62,7 +62,7 @@ function getService() {
6262
* Handles the OAuth callback.
6363
*/
6464
function authCallback(request) {
65-
var service = getService();
65+
var service = getService_();
6666
var authorized = service.handleCallback(request);
6767
if (authorized) {
6868
return HtmlService.createHtmlOutput('Success!');

samples/XeroPrivate.gs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ var PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n
1919
* Authorizes and makes a request to the Xero API.
2020
*/
2121
function run() {
22-
var service = getService();
22+
var service = getService_();
2323
var url = 'https://api.xero.com/api.xro/2.0/Organisations';
2424
var response = service.fetch(url, {
2525
headers: {
@@ -34,13 +34,13 @@ function run() {
3434
* Reset the authorization state, so that it can be re-tested.
3535
*/
3636
function reset() {
37-
getService().reset();
37+
getService_().reset();
3838
}
3939

4040
/**
4141
* Configures the service.
4242
*/
43-
function getService() {
43+
function getService_() {
4444
return OAuth1.createService('Xero')
4545
// Set the consumer key and secret.
4646
.setConsumerKey(CONSUMER_KEY)

0 commit comments

Comments
 (0)