Skip to content

Commit d8d4e05

Browse files
committed
Initial commit
0 parents  commit d8d4e05

File tree

5 files changed

+276
-0
lines changed

5 files changed

+276
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
.idea

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) Andrew Smith
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
oauth-1-client
2+
==============
3+
4+
Promise-based OAuth 1 client for node.js
5+
6+
# Install
7+
8+
```
9+
npm install oauth-1-client
10+
```
11+
12+
# Overview
13+
14+
Promise-based OAuth 1 client for node.js based on the [node-auth](https://github.com/ciaranj/node-oauth) library.
15+
16+
# Usage
17+
18+
```
19+
var odeskClient = new OAuth1Client({
20+
key: odeskConfig.apiKey,
21+
secret: odeskConfig.sharedSecret,
22+
callbackURL: odeskConfig.callbackURL,
23+
requestUrl: 'https://www.odesk.com/api/auth/v1/oauth/token/request',
24+
accessUrl: 'https://www.odesk.com/api/auth/v1/oauth/token/access',
25+
apiHostName: 'www.odesk.com'
26+
});
27+
```
28+
29+
Note: The `apiHostName` option is used to construct a base URL (https:// based) for all relative paths. See below.
30+
31+
Each method on the API returns back a Javascript promise object.
32+
33+
If using a version of node which supports ES6 generators, a sample usage might look like:
34+
35+
```
36+
var response = yield odeskClient.requestToken();
37+
38+
var tempCredentials = {
39+
token: response.token,
40+
tokenSecret: response.tokenSecret
41+
};
42+
43+
// Store `tempCredentials` somewhere and redirect user
44+
// (there might be a URL provided in `response.authorizeUrl` - consult your OAuth provider docs).
45+
```
46+
47+
Then in your OAuth callback:
48+
49+
```
50+
var verifier = (get it from URL or request header depending on your provider);
51+
var prevCredentials = (load previously stored credentials from above);
52+
var response = yield odeskClient.accessToken(prevCredentials.token, prevCredentials.tokenSecret, verifier);
53+
54+
var finalCredentials = {
55+
token: response.token,
56+
tokenSecret: response.tokenSecret
57+
};
58+
// store `finalCredentials` somewhere
59+
60+
// Good to go now. Make sure to call .auth(...) function first to set the credentials:
61+
var authODeskClient = odeskClient.auth(finalCredentials.token, finalCredentials.tokenSecret);
62+
63+
// Then use get/put/post/delte methods as you'd expect:
64+
var relativeUrl = util.format('/gds/timereports/v1/providers/%s/hours', userRef);
65+
var response = yield authODeskClient.get(relativeUrl, params);
66+
```
67+
68+
# License
69+
70+
MIT

lib/index.js

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
var assert = require('assert');
2+
var OAuth = require('OAuth');
3+
var url = require('url');
4+
var Promise = require('promise');
5+
6+
require('extend-error');
7+
var HttpApiError = Error.extend('HttpApiError');
8+
9+
var Client = function(options) {
10+
assert(options.key, 'Must provide API key');
11+
assert(options.secret, 'Must provide API secret');
12+
assert(options.callbackURL, 'Must provide API callbackURL');
13+
assert(options.requestUrl, 'Must provide requestUrl');
14+
assert(options.accessUrl, 'Must provide accessUrl');
15+
assert(options.apiHostName, 'Must provide apiHostName');
16+
17+
this.apiKey = options.key;
18+
this.apiSecret = options.secret;
19+
this.callbackURL = options.callbackURL;
20+
this.apiHostName = options.apiHostName;
21+
22+
this.oauthClient = new OAuth.OAuth(
23+
options.requestUrl,
24+
options.accessUrl,
25+
this.apiKey,
26+
this.apiSecret,
27+
'1.0',
28+
this.callbackURL,
29+
'HMAC-SHA1');
30+
};
31+
32+
Client.prototype.auth = function(token, secret) {
33+
assert(token, 'Must provide token');
34+
assert(secret, 'Must provide secret');
35+
36+
this.authenticatedToken = token;
37+
this.authenticatedSecret = secret;
38+
return this;
39+
};
40+
41+
Client.prototype.get = function(path, pageOrQuery) {
42+
assert(this.authenticatedToken, 'Must set authentication token first');
43+
assert(this.authenticatedSecret, 'Must set authentication secret first');
44+
45+
var url = buildUrl(this.apiKey, this.apiSecret, this.apiHostName, path, pageOrQuery);
46+
return new Promise(function(resolve, reject) {
47+
var responseHandler = createResponseHandler(resolve, reject);
48+
this.oauthClient.get(url, this.authenticatedToken, this.authenticatedSecret, responseHandler);
49+
}.bind(this));
50+
};
51+
52+
Client.prototype.put = function(path, content) {
53+
assert(this.authenticatedToken, 'Must set authentication token first');
54+
assert(this.authenticatedSecret, 'Must set authentication secret first');
55+
56+
var url = buildUrl(this.apiKey, this.apiSecret, this.apiHostName, path);
57+
return new Promise(function(resolve, reject) {
58+
var responseHandler = createResponseHandler(resolve, reject);
59+
this.oauthClient.put(url, this.authenticatedToken, this.authenticatedSecret, content, responseHandler);
60+
}.bind(this));
61+
};
62+
63+
Client.prototype.post = function(path, content) {
64+
assert(this.authenticatedToken, 'Must set authentication token first');
65+
assert(this.authenticatedSecret, 'Must set authentication secret first');
66+
67+
var url = buildUrl(this.apiKey, this.apiSecret, this.apiHostName, path);
68+
return new Promise(function(resolve, reject) {
69+
var responseHandler = createResponseHandler(resolve, reject);
70+
this.oauthClient.post(url, this.authenticatedToken, this.authenticatedSecret, content, responseHandler);
71+
}.bind(this));
72+
};
73+
74+
Client.prototype['delete'] = function(path) {
75+
assert(this.authenticatedToken, 'Must set authentication token first');
76+
assert(this.authenticatedSecret, 'Must set authentication secret first');
77+
78+
var url = buildUrl(this.apiKey, this.apiSecret, this.apiHostName, path);
79+
return new Promise(function(resolve, reject) {
80+
var responseHandler = createResponseHandler(resolve, reject);
81+
this.oauthClient['delete'](url, this.authenticatedToken, this.authenticatedSecret, responseHandler);
82+
}.bind(this));
83+
};
84+
85+
Client.prototype.requestToken = function(extraParams) {
86+
return new Promise(function(resolve, reject) {
87+
this.oauthClient.getOAuthRequestToken(extraParams || {}, function(err, oauthToken, oauthTokenSecret, parsedQueryString) {
88+
if (err) {
89+
return reject(err);
90+
}
91+
resolve({
92+
token: oauthToken,
93+
tokenSecret: oauthTokenSecret,
94+
authorizeUrl: parsedQueryString.login_url
95+
});
96+
});
97+
}.bind(this));
98+
};
99+
100+
Client.prototype.accessToken = function(token, secret, verifier) {
101+
return new Promise(function(resolve, reject) {
102+
this.oauthClient.getOAuthAccessToken(token, secret, verifier, function (err, oauthAccessToken, oauthAccessTokenSecret) {
103+
if (err) {
104+
return reject(err);
105+
}
106+
resolve({
107+
token: oauthAccessToken,
108+
tokenSecret: oauthAccessTokenSecret
109+
});
110+
});
111+
}.bind(this));
112+
};
113+
114+
function createResponseHandler(resolve, reject) {
115+
return function responseHandler(err, data, res) {
116+
if (res.statusCode.toString()[0] !== '2') {
117+
return reject(new HttpApiError({ statusCode: res.statusCode, body: data }));
118+
}
119+
if (typeof data === 'string') {
120+
try {
121+
var parsedBody = JSON.parse(data || '{}');
122+
resolve({
123+
statusCode: res.statusCode,
124+
body: parsedBody,
125+
headers: res.headers
126+
});
127+
} catch (err) {
128+
reject('Error parsing JSON response from API. Error:' + err);
129+
}
130+
}
131+
};
132+
}
133+
134+
function buildUrl(apiKey, apiSecret, apiHostName, path, pageOrQuery) {
135+
if (apiKey === null) {
136+
throw new Error('Must provide apiKey');
137+
}
138+
if (apiSecret === null) {
139+
throw new Error('Must provide apiSecret');
140+
}
141+
if (path === null) {
142+
throw new Error('Must provide a path');
143+
}
144+
var query = (pageOrQuery && typeof pageOrQuery === 'object')
145+
? pageOrQuery
146+
: {};
147+
if (apiKey && !apiSecret) {
148+
query.api_key = this.apiKey;
149+
}
150+
return url.format({
151+
protocol: "https:",
152+
hostname: apiHostName,
153+
pathname: path,
154+
query: query
155+
});
156+
}
157+
158+
module.exports = Client;

package.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "oauth-1-client",
3+
"version": "0.0.1",
4+
"description": "Promise-based OAuth 1 client",
5+
"main": "lib/index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "https://github.com/emertechie/oauth-1-client"
12+
},
13+
"keywords": [
14+
"oauth",
15+
"oauth1",
16+
"promise"
17+
],
18+
"author": "[email protected]",
19+
"license": "MIT",
20+
"dependencies": {
21+
"extend-error": "0.0.2",
22+
"oauth": "^0.9.12",
23+
"promise": "^6.1.0"
24+
}
25+
}

0 commit comments

Comments
 (0)