Skip to content

Commit a5480c1

Browse files
authored
fix: prevent samples from leaking OAuth client ID + Secret to users (#379)
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 72d4dbc commit a5480c1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+214
-210
lines changed

README.md

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ exact URL that the service will use when performing the OAuth flow:
7878
* Logs the redirect URI to register.
7979
*/
8080
function logRedirectUri() {
81-
var service = getService();
81+
var service = getService_();
8282
Logger.log(service.getRedirectUri());
8383
}
8484
```
@@ -95,8 +95,12 @@ information is not persisted to any data store, so you'll need to create this
9595
object each time you want to use it. The example below shows how to create a
9696
service for the Google Drive API.
9797

98+
Ensure the method is private (has an underscore at the end of the name) to
99+
prevent clients from being able to call the method to read your client ID and
100+
secret.
101+
98102
```js
99-
function getDriveService() {
103+
function getDriveService_() {
100104
// Create a new service with the given name. The name will be used when
101105
// persisting the authorized token, so ensure it is unique within the
102106
// scope of the property store.
@@ -143,7 +147,7 @@ The URL is generated by the service, using the function `getAuthorizationUrl()`.
143147

144148
```js
145149
function showSidebar() {
146-
var driveService = getDriveService();
150+
var driveService = getDriveService_();
147151
if (!driveService.hasAccess()) {
148152
var authorizationUrl = driveService.getAuthorizationUrl();
149153
var template = HtmlService.createTemplate(
@@ -167,7 +171,7 @@ to the user.
167171

168172
```js
169173
function authCallback(request) {
170-
var driveService = getDriveService();
174+
var driveService = getDriveService_();
171175
var isAuthorized = driveService.handleCallback(request);
172176
if (isAuthorized) {
173177
return HtmlService.createHtmlOutput('Success! You can close this tab.');
@@ -190,7 +194,7 @@ request in the "Authorization" header.
190194

191195
```js
192196
function makeRequest() {
193-
var driveService = getDriveService();
197+
var driveService = getDriveService_();
194198
var response = UrlFetchApp.fetch('https://www.googleapis.com/drive/v2/files?maxResults=10', {
195199
headers: {
196200
Authorization: 'Bearer ' + driveService.getAccessToken()
@@ -208,7 +212,7 @@ different account, use the `reset()` method:
208212

209213
```js
210214
function logout() {
211-
var service = getDriveService()
215+
var service = getDriveService_()
212216
service.reset();
213217
}
214218
```
@@ -350,7 +354,7 @@ request parameters and saved saved into storage.
350354

351355
```js
352356
function authCallback(request) {
353-
var service = getService();
357+
var service = getService_();
354358
var authorized = service.handleCallback(request);
355359
if (authorized) {
356360
// Gets the authorized account ID from the scope string. Assumes the
@@ -401,7 +405,7 @@ optional hash of parameter names and values to the `getAuthorizationUrl()`
401405
method:
402406
403407
```js
404-
var authorizationUrl = getService().getAuthorizationUrl({
408+
var authorizationUrl = getService_().getAuthorizationUrl({
405409
// Pass the additional parameter "lang" with the value "fr".
406410
lang: 'fr'
407411
});
@@ -467,17 +471,17 @@ means selecting a service name that matches the API the user will authorize:
467471
468472
```js
469473
function run() {
470-
var gitHubService = getGitHubService();
471-
var mediumService = getMediumService();
474+
var gitHubService = getGitHubService_();
475+
var mediumService = getMediumService_();
472476
// ...
473477
}
474478

475-
function getGitHubService() {
479+
function getGitHubService_() {
476480
return OAuth2.createService('GitHub')
477481
// GitHub settings ...
478482
}
479483

480-
function getMediumService() {
484+
function getMediumService_() {
481485
return OAuth2.createService('Medium')
482486
// Medium settings ...
483487
}
@@ -490,12 +494,12 @@ names:
490494
491495
```js
492496
function run() {
493-
var copyFromService = getGitHubService('from');
494-
var copyToService = getGitHubService('to');
497+
var copyFromService = getGitHubService_('from');
498+
var copyToService = getGitHubService_('to');
495499
// ...
496500
}
497501

498-
function getGitHubService(label) {
502+
function getGitHubService_(label) {
499503
return OAuth2.createService('GitHub_' + label)
500504
// GitHub settings ...
501505
}

docs/index.html

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ <h2>Redirect URI</h2>
119119
* Logs the redirect URI to register.
120120
*/
121121
function logRedirectUri() {
122-
var service = getService();
122+
var service = getService_();
123123
Logger.log(service.getRedirectUri());
124124
}
125125
</code></pre>
@@ -131,7 +131,7 @@ <h3>1. Create the OAuth2 service</h3>
131131
information is not persisted to any data store, so you'll need to create this
132132
object each time you want to use it. The example below shows how to create a
133133
service for the Google Drive API.</p>
134-
<pre class="prettyprint source lang-js"><code>function getDriveService() {
134+
<pre class="prettyprint source lang-js"><code>function getDriveService_() {
135135
// Create a new service with the given name. The name will be used when
136136
// persisting the authorized token, so ensure it is unique within the
137137
// scope of the property store.
@@ -174,7 +174,7 @@ <h3>2. Direct the user to the authorization URL</h3>
174174
you'll need to present the authorization URL as a link for the user to click.
175175
The URL is generated by the service, using the function <code>getAuthorizationUrl()</code>.</p>
176176
<pre class="prettyprint source lang-js"><code>function showSidebar() {
177-
var driveService = getDriveService();
177+
var driveService = getDriveService_();
178178
if (!driveService.hasAccess()) {
179179
var authorizationUrl = driveService.getAuthorizationUrl();
180180
var template = HtmlService.createTemplate(
@@ -194,7 +194,7 @@ <h3>3. Handle the callback</h3>
194194
request object to the service's <code>handleCallback</code> function, and show a message
195195
to the user.</p>
196196
<pre class="prettyprint source lang-js"><code>function authCallback(request) {
197-
var driveService = getDriveService();
197+
var driveService = getDriveService_();
198198
var isAuthorized = driveService.handleCallback(request);
199199
if (isAuthorized) {
200200
return HtmlService.createHtmlOutput('Success! You can close this tab.');
@@ -212,7 +212,7 @@ <h3>4. Get the access token</h3>
212212
requests to the API. The access token can be passed along with a <code>UrlFetchApp</code>
213213
request in the &quot;Authorization&quot; header.</p>
214214
<pre class="prettyprint source lang-js"><code>function makeRequest() {
215-
var driveService = getDriveService();
215+
var driveService = getDriveService_();
216216
var response = UrlFetchApp.fetch('https://www.googleapis.com/drive/v2/files?maxResults=10', {
217217
headers: {
218218
Authorization: 'Bearer ' + driveService.getAccessToken()
@@ -225,7 +225,7 @@ <h3>Logout</h3>
225225
<p>To logout the user or disconnect the service, perhaps so the user can select a
226226
different account, use the <code>reset()</code> method:</p>
227227
<pre class="prettyprint source lang-js"><code>function logout() {
228-
var service = getDriveService()
228+
var service = getDriveService_()
229229
service.reset();
230230
}
231231
</code></pre>
@@ -326,7 +326,7 @@ <h4>Storing token-related data</h4>
326326
in the callback URL. In the following code the account ID is extracted from the
327327
request parameters and saved saved into storage.</p>
328328
<pre class="prettyprint source lang-js"><code>function authCallback(request) {
329-
var service = getService();
329+
var service = getService_();
330330
var authorized = service.handleCallback(request);
331331
if (authorized) {
332332
// Gets the authorized account ID from the scope string. Assumes the
@@ -368,7 +368,7 @@ <h4>Passing additional parameters to the callback function</h4>
368368
token, which is a standard mechanism for this purpose. To do so, pass an
369369
optional hash of parameter names and values to the <code>getAuthorizationUrl()</code>
370370
method:</p>
371-
<pre class="prettyprint source lang-js"><code>var authorizationUrl = getService().getAuthorizationUrl({
371+
<pre class="prettyprint source lang-js"><code>var authorizationUrl = getService_().getAuthorizationUrl({
372372
// Pass the additional parameter &quot;lang&quot; with the value &quot;fr&quot;.
373373
lang: 'fr'
374374
});
@@ -419,17 +419,17 @@ <h3>How can I connect to multiple OAuth services?</h3>
419419
multiple services merely ensure they have different service names. Often this
420420
means selecting a service name that matches the API the user will authorize:</p>
421421
<pre class="prettyprint source lang-js"><code>function run() {
422-
var gitHubService = getGitHubService();
423-
var mediumService = getMediumService();
422+
var gitHubService = getGitHubService_();
423+
var mediumService = getMediumService_();
424424
// ...
425425
}
426426

427-
function getGitHubService() {
427+
function getGitHubService_() {
428428
return OAuth2.createService('GitHub')
429429
// GitHub settings ...
430430
}
431431

432-
function getMediumService() {
432+
function getMediumService_() {
433433
return OAuth2.createService('Medium')
434434
// Medium settings ...
435435
}
@@ -439,12 +439,12 @@ <h3>How can I connect to multiple OAuth services?</h3>
439439
those cases you'll need to devise your own method for creating unique service
440440
names:</p>
441441
<pre class="prettyprint source lang-js"><code>function run() {
442-
var copyFromService = getGitHubService('from');
443-
var copyToService = getGitHubService('to');
442+
var copyFromService = getGitHubService_('from');
443+
var copyToService = getGitHubService_('to');
444444
// ...
445445
}
446446

447-
function getGitHubService(label) {
447+
function getGitHubService_(label) {
448448
return OAuth2.createService('GitHub_' + label)
449449
// GitHub settings ...
450450
}

samples/Add-on/Code.gs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function onInstall(e) {
4949
* project file.
5050
*/
5151
function showSidebar() {
52-
var service = getGitHubService();
52+
var service = getGitHubService_();
5353
var template = HtmlService.createTemplateFromFile('Sidebar');
5454
template.email = Session.getEffectiveUser().getEmail();
5555
template.isSignedIn = service.hasAccess();
@@ -64,22 +64,22 @@ function showSidebar() {
6464
* @return {String} The authorization URL.
6565
*/
6666
function getAuthorizationUrl() {
67-
return getGitHubService().getAuthorizationUrl();
67+
return getGitHubService_().getAuthorizationUrl();
6868
}
6969

7070
/**
7171
* Resets the API service, forcing re-authorization before
7272
* additional authorization-required API calls can be made.
7373
*/
7474
function signOut() {
75-
getGitHubService().reset();
75+
getGitHubService_().reset();
7676
}
7777

7878
/**
7979
* Gets the user's GitHub profile.
8080
*/
8181
function getGitHubProfile() {
82-
var service = getGitHubService();
82+
var service = getGitHubService_();
8383
if (!service.hasAccess()) {
8484
throw new Error('Error: Missing GitHub authorization.');
8585
}
@@ -96,7 +96,7 @@ function getGitHubProfile() {
9696
* Gets the user's GitHub repos.
9797
*/
9898
function getGitHubRepos() {
99-
var service = getGitHubService();
99+
var service = getGitHubService_();
100100
if (!service.hasAccess()) {
101101
throw new Error('Error: Missing GitHub authorization.');
102102
}
@@ -113,7 +113,7 @@ function getGitHubRepos() {
113113
* Gets an OAuth2 service configured for the GitHub API.
114114
* @return {OAuth2.Service} The OAuth2 service
115115
*/
116-
function getGitHubService() {
116+
function getGitHubService_() {
117117
return OAuth2.createService('github')
118118
// Set the endpoint URLs.
119119
.setAuthorizationBaseUrl('https://github.com/login/oauth/authorize')
@@ -142,7 +142,7 @@ function authCallback(request) {
142142
template.error = null;
143143
var title;
144144
try {
145-
var service = getGitHubService();
145+
var service = getGitHubService_();
146146
var authorized = service.handleCallback(request);
147147
template.isSignedIn = authorized;
148148
title = authorized ? 'Access Granted' : 'Access Denied';

samples/AdobeSign.gs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ var API_ACCESS_POINT_KEY = 'api_access_point';
1212
* Authorizes and makes a request to the Adobe Sign API.
1313
*/
1414
function run() {
15-
var service = getService();
15+
var service = getService_();
1616
if (service.hasAccess()) {
1717
// Retrieve the API access point from storage.
1818
var apiAccessPoint = service.getStorage().getValue(API_ACCESS_POINT_KEY);
@@ -38,13 +38,13 @@ function run() {
3838
* Reset the authorization state, so that it can be re-tested.
3939
*/
4040
function reset() {
41-
getService().reset();
41+
getService_().reset();
4242
}
4343

4444
/**
4545
* Configures the service.
4646
*/
47-
function getService(optApiAccessPoint) {
47+
function getService_(optApiAccessPoint) {
4848
var service = OAuth2.createService('AdobeSign')
4949
// Set the endpoint URLs.
5050
.setAuthorizationBaseUrl('https://secure.echosign.com/public/oauth')
@@ -82,7 +82,7 @@ function getService(optApiAccessPoint) {
8282
function authCallback(request) {
8383
// Get the API access point specified in the URL parameters.
8484
var apiAccessPoint = request.parameter[API_ACCESS_POINT_KEY];
85-
var service = getService(apiAccessPoint);
85+
var service = getService_(apiAccessPoint);
8686
var authorized = service.handleCallback(request);
8787
if (authorized) {
8888
// Save the API access point in the service's storage.

samples/Basecamp.gs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var CLIENT_SECRET = '...';
55
* Authorizes and makes a request to the Basecamp 3 API.
66
*/
77
function run() {
8-
var service = getService();
8+
var service = getService_();
99
if (service.hasAccess()) {
1010
var url = 'https://launchpad.37signals.com/authorization.json';
1111
var response = UrlFetchApp.fetch(url, {
@@ -26,13 +26,13 @@ function run() {
2626
* Reset the authorization state, so that it can be re-tested.
2727
*/
2828
function reset() {
29-
getService().reset();
29+
getService_().reset();
3030
}
3131

3232
/**
3333
* Configures the service.
3434
*/
35-
function getService() {
35+
function getService_() {
3636
return OAuth2.createService('Basecamp')
3737
// Set the endpoint URLs.
3838
.setAuthorizationBaseUrl(
@@ -56,7 +56,7 @@ function getService() {
5656
* Handles the OAuth callback.
5757
*/
5858
function authCallback(request) {
59-
var service = getService();
59+
var service = getService_();
6060
var authorized = service.handleCallback(request);
6161
if (authorized) {
6262
return HtmlService.createHtmlOutput('Success!');

samples/ChatWork.gs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var CLIENT_SECRET = '...';
55
* Authorizes and makes a request to the ChatWork API.
66
*/
77
function run() {
8-
var service = getService();
8+
var service = getService_();
99
if (service.hasAccess()) {
1010
var response = UrlFetchApp.fetch('https://api.chatwork.com/v2/me', {
1111
headers: {
@@ -25,13 +25,13 @@ function run() {
2525
* Reset the authorization state, so that it can be re-tested.
2626
*/
2727
function reset() {
28-
getService().reset();
28+
getService_().reset();
2929
}
3030

3131
/**
3232
* Configures the service.
3333
*/
34-
function getService() {
34+
function getService_() {
3535
var scope = 'users.profile.me:read rooms.messages:read';
3636
return OAuth2.createService('ChatWork')
3737
// Set the endpoint URLs.
@@ -67,7 +67,7 @@ function getService() {
6767
* Handles the OAuth callback.
6868
*/
6969
function authCallback(request) {
70-
var service = getService();
70+
var service = getService_();
7171
var authorized = service.handleCallback(request);
7272
if (authorized) {
7373
return HtmlService.createHtmlOutput('Success!');

0 commit comments

Comments
 (0)