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

Commit c0f66de

Browse files
author
Eric Koleda
committed
Add support for 2-legged OAuth, Yelp sample (which uses 2-legged), and fix a signing bug the sample revealed.
1 parent c3055ca commit c0f66de

File tree

4 files changed

+143
-7
lines changed

4 files changed

+143
-7
lines changed

MemoryProperties.gs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* Creates a new MemoryProperties, an implementation of the Properties
3+
* interface that stores values in memory.
4+
* @constructor
5+
*/
6+
var MemoryProperties = function() {
7+
this.properties = {};
8+
};
9+
10+
/**
11+
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#deleteallproperties}
12+
*/
13+
MemoryProperties.prototype.deleteAllProperties = function() {
14+
this.properties = {};
15+
};
16+
17+
/**
18+
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#deletepropertykey}
19+
*/
20+
MemoryProperties.prototype.deleteProperty = function(key) {
21+
delete this.properties[key];
22+
};
23+
24+
/**
25+
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#getkeys}
26+
*/
27+
MemoryProperties.prototype.getKeys = function() {
28+
return Object.keys(this.properties);
29+
}
30+
31+
/**
32+
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#getproperties}
33+
*/
34+
MemoryProperties.prototype.getProperties = function() {
35+
return _.clone(this.properties);
36+
}
37+
38+
/**
39+
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#getproperty}
40+
*/
41+
MemoryProperties.prototype.getProperty = function(key) {
42+
return this.properties[key];
43+
}
44+
45+
/**
46+
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#setpropertiesproperties-deleteallothers}
47+
*/
48+
MemoryProperties.prototype.setProperties = function(properties, opt_deleteAllOthers) {
49+
if (opt_deleteAllOthers) {
50+
this.deleteAllProperties();
51+
}
52+
Object.keys(properties).forEach(function(key) {
53+
this.setProperty(key, properties[key]);
54+
});
55+
};
56+
57+
/**
58+
* @see {@link https://developers.google.com/apps-script/reference/properties/properties#setpropertykey-value}
59+
*/
60+
MemoryProperties.prototype.setProperty = function(key, value) {
61+
this.properties[key] = String(value);
62+
};

Service.gs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ var Service_ = function(serviceName) {
3131
this.oauthVersion_ = '1.0a';
3232
this.projectKey_ = eval('Script' + 'App').getProjectKey();
3333
this.signatureMethod_ = 'HMAC-SHA1';
34+
this.propertyStore_ = new MemoryProperties();
3435
};
3536

3637
/**
@@ -98,7 +99,7 @@ Service_.prototype.setMethod = function(method) {
9899

99100
/**
100101
* Sets the OAuth signature method to use. 'HMAC-SHA1' is the default.
101-
* @param {string} signatureMethod The OAuth signature method. Allowed values
102+
* @param {string} signatureMethod The OAuth signature method. Allowed values
102103
* are 'HMAC-SHA1' and 'PLAINTEXT'.
103104
* @return {Service_} This service, for chaining.
104105
*/
@@ -171,10 +172,10 @@ Service_.prototype.setConsumerSecret = function(consumerSecret) {
171172
};
172173

173174
/**
174-
* Sets the property store to use when persisting credentials (required). In
175+
* Sets the property store to use when persisting credentials (optional). In
175176
* most cases this should be user properties, but document or script properties
176-
* may be appropriate if you want
177-
* to share access across users.
177+
* may be appropriate if you want to share access across users. If not set tokens
178+
* will be stored in memory only.
178179
* @param {PropertiesService.Properties} propertyStore The property store to use
179180
* when persisting credentials.
180181
* @return {Service_} This service, for chaining.
@@ -198,6 +199,22 @@ Service_.prototype.setCache = function(cache) {
198199
return this;
199200
};
200201

202+
/**
203+
* Sets the access token and token secret to use (optional). For use with APIs
204+
* that support a 1-legged flow where no user interaction is required.
205+
* @param {string} token The access token.
206+
* @param {string} secret The token secret.
207+
* @return {Service_} This service, for chaining.
208+
*/
209+
Service_.prototype.setAccessToken = function(token, secret) {
210+
this.saveToken_({
211+
public: token,
212+
secret: secret,
213+
type: 'access'
214+
});
215+
return this;
216+
};
217+
201218
/**
202219
* Starts the authorization process. A new token will be generated and the
203220
* authorization URL for that token will be returned. Have the user visit this
@@ -381,7 +398,6 @@ Service_.prototype.fetchInternal_ = function(url, params, opt_token,
381398
secret: this.consumerSecret_
382399
}
383400
});
384-
var payload = _.extend({}, params.payload, oauthParams);
385401
var request = {
386402
url: url,
387403
method: params.method

Signer.gs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,14 @@
192192
* @return {Object}
193193
*/
194194
OAuth.prototype.deParam = function(string) {
195-
var arr = string.split('&');
195+
var arr = decodeURIComponent(string)
196+
.replace(/\+/g, ' ')
197+
.split('&');
196198
var data = {};
197199

198200
for(var i = 0; i < arr.length; i++) {
199201
var item = arr[i].split('=');
200-
data[item[0]] = decodeURIComponent(item[1]);
202+
data[item[0]] = item[1];
201203
}
202204
return data;
203205
};

samples/Yelp.gs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
var CONSUMER_KEY = '...';
2+
var CONSUMER_SECRET = '...';
3+
var TOKEN = '...';
4+
var TOKEN_SECRET = '...';
5+
6+
/**
7+
* Authorizes and makes a request to the Yelp API.
8+
*/
9+
function run() {
10+
var service = getService();
11+
if (service.hasAccess()) {
12+
var url = 'https://api.yelp.com/v2/search?term=food&location=San+Francisco';
13+
var response = service.fetch(url);
14+
var result = JSON.parse(response.getContentText());
15+
Logger.log(JSON.stringify(result, null, 2));
16+
} else {
17+
var authorizationUrl = service.authorize();
18+
Logger.log('Open the following URL and re-run the script: %s',
19+
authorizationUrl);
20+
}
21+
}
22+
23+
/**
24+
* Reset the authorization state, so that it can be re-tested.
25+
*/
26+
function reset() {
27+
var service = getService();
28+
service.reset();
29+
}
30+
31+
/**
32+
* Configures the service.
33+
*/
34+
function getService() {
35+
return OAuth1.createService('Yelp')
36+
// Set the consumer key and secret.
37+
.setConsumerKey(CONSUMER_KEY)
38+
.setConsumerSecret(CONSUMER_SECRET)
39+
40+
// Manually set the token and secret, as provided by the Yelp developer
41+
// console.
42+
.setAccessToken(TOKEN, TOKEN_SECRET);
43+
}
44+
45+
/**
46+
* Handles the OAuth2 callback.
47+
*/
48+
function authCallback(request) {
49+
var service = getService();
50+
var authorized = service.handleCallback(request);
51+
if (authorized) {
52+
return HtmlService.createHtmlOutput('Success!');
53+
} else {
54+
return HtmlService.createHtmlOutput('Denied');
55+
}
56+
}

0 commit comments

Comments
 (0)