Created
December 1, 2013 04:55
-
-
Save warmwaffles/7728653 to your computer and use it in GitHub Desktop.
Based loosely on `simple-oauth2`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
require('date-utils'); | |
var underscore = require('underscore'); | |
/** | |
* Constructs a brand new AccessToken | |
* | |
* @param client {OAuth2.Client} The OAuth2 client that will be used for | |
* requests. | |
* @param token {String} The access token. A null can be provided, but a | |
* refresh token must be passed in with the options. | |
* @param options {Object} Allowable options include the following: | |
* @option options refreshToken {String} This must be provided if the token | |
* that was passed is null. | |
* @option options expiresAt {Date} If this is not provided it will be assumed | |
* that the token will expire in 120 seconds from now. | |
* @constructor | |
*/ | |
function AccessToken(client, token, options) { | |
options = options || {}; | |
this.client = client; | |
this.token = token; | |
this.refreshToken = options.refreshToken || null; | |
if (this.token === null && this.refreshToken === null) { | |
throw new Error('a token or refreshToken must be provided'); | |
} | |
this.expiresAt = options.expiresAt || new Date().addSeconds(120); | |
this.authorizePath = options.authorizePath || '/oauth/authorize'; | |
this.tokenPath = options.tokenPath || '/oauth/token'; | |
this.params = options; | |
} | |
AccessToken.prototype.get = function (path, params, callback) { | |
return this.execute('GET', path, params, callback); | |
}; | |
AccessToken.prototype.post = function (path, params, callback) { | |
return this.execute('POST', path, params, callback); | |
}; | |
AccessToken.prototype.put = function (path, params, callback) { | |
return this.execute('PUT', path, params, callback); | |
}; | |
AccessToken.prototype.del = function (path, params, callback) { | |
return this.execute('DELETE', path, params, callback); | |
}; | |
AccessToken.prototype.head = function (path, params, callback) { | |
return this.execute('HEAD', path, params, callback); | |
}; | |
AccessToken.prototype.execute = function (method, path, params, callback) { | |
var headers = { | |
'Authorization': 'Bearer ' + this.token | |
}; | |
return this.client.execute(method, path, params, headers, callback); | |
}; | |
/** | |
* Refreshes the current access token. | |
* | |
* @param callback {function} Is called when the request is complete | |
*/ | |
AccessToken.prototype.refresh = function (callback) { | |
if (this.refreshToken === undefined || this.refreshToken === null) { | |
throw new Error('refreshToken is not set'); | |
} | |
// Clear the old token | |
this.token = null; | |
var params = { | |
grant_type: 'refresh_token', | |
refresh_token: this.refreshToken, | |
client_id: this.client.id, | |
client_secret: this.client.secret | |
}, | |
self = this, | |
now = new Date(); | |
this.client.post(this.tokenPath, params, function (error, results) { | |
if (results) { | |
self.token = results.access_token; | |
self.expiresAt = now.addSeconds(results.expires_in); | |
} | |
callback(error, results); | |
}); | |
}; | |
/** | |
* Check to see if the access token is expired | |
* @returns {boolean} | |
*/ | |
AccessToken.prototype.hasExpired = function () { | |
return Date.compare(this.expiresAt, new Date()) === -1; | |
}; | |
module.exports = AccessToken; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var request = require('request'), | |
crypto = require('crypto'), | |
util = require("util"), | |
underscore = require('underscore'), | |
HTTPError = require('./http_error'); | |
/** | |
* | |
* @param id {String} the client id | |
* @param secret {String} the client secret | |
* @param site {String} the OAuth2 provider site host | |
* @param options {Object} | |
* @constructor | |
*/ | |
function Client(id, secret, site, options) { | |
options = options || {}; | |
this.id = id; | |
this.secret = secret; | |
this.site = site; | |
this.clientSecretParameterName = options.clientSecretParameterName || 'client_secret'; | |
this.params = options; | |
} | |
/** | |
* Performs a GET request | |
* | |
* @param path {String} | |
* @param params {Object} | |
* @param headers {Object} | |
* @param callback {function} | |
* @returns what the callback returns | |
*/ | |
Client.prototype.get = function (path, params, headers, callback) { | |
return this.execute('GET', path, params, headers, callback); | |
}; | |
/** | |
* Performs a POST request | |
* | |
* @param path {String} | |
* @param params {Object} | |
* @param headers {Object} | |
* @param callback {function} | |
* @returns what the callback returns | |
*/ | |
Client.prototype.post = function (path, params, headers, callback) { | |
return this.execute('POST', path, params, headers, callback); | |
}; | |
/** | |
* Performs a PUT request | |
* | |
* @param path {String} | |
* @param params {Object} | |
* @param headers {Object} | |
* @param callback {function} | |
* @returns what the callback returns | |
*/ | |
Client.prototype.put = function (path, params, headers, callback) { | |
return this.execute('PUT', path, params, headers, callback); | |
}; | |
/** | |
* Performs a DELETE request | |
* | |
* @param path {String} | |
* @param params {Object} | |
* @param headers {Object} | |
* @param callback {function} | |
* @returns what the callback returns | |
*/ | |
Client.prototype.del = function (path, params, headers, callback) { | |
return this.execute('DELETE', path, params, headers, callback); | |
}; | |
/** | |
* Performs a PATCH request | |
* | |
* @param path {String} | |
* @param params {Object} | |
* @param headers {Object} | |
* @param callback {function} | |
* @returns what the callback returns | |
*/ | |
Client.prototype.patch = function (path, params, headers, callback) { | |
return this.execute('PATCH', path, params, headers, callback); | |
}; | |
/** | |
* Performs a HEAD request | |
* | |
* @param path {String} | |
* @param params {Object} | |
* @param headers {Object} | |
* @param callback {function} | |
* @returns what the callback returns | |
*/ | |
Client.prototype.head = function (path, params, headers, callback) { | |
return this.execute('HEAD', path, params, headers, callback); | |
}; | |
/** | |
* | |
* @param method {String} the http verb | |
* @param path {String} the relative path of the resource | |
* @param params {Object} | |
* @param headers {Object} | |
* @param callback {function} | |
*/ | |
Client.prototype.execute = function (method, path, params, headers, callback) { | |
if (!this.id || !this.secret || !this.site) { | |
throw new Error('Client is no properly configured'); | |
} | |
if (!callback || typeof callback !== 'function') { | |
throw new Error('Callback not provided on API call'); | |
} | |
var options = { | |
uri: this.site + path, | |
method: method, | |
headers: headers || {} | |
}; | |
if (method === 'GET') { | |
options.qs = params; | |
} else { | |
options.form = params; | |
} | |
request(options, function (error, response, body) { | |
if (error) { | |
return callback(error, body); | |
} | |
try { | |
body = JSON.parse(body); | |
} catch (e) { | |
console.error(e); | |
} | |
if (response.statusCode >= 400) { | |
return callback(new HTTPError(response.statusCode), null); | |
} | |
return callback(error, body); | |
}); | |
}; | |
module.exports = Client; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var statusCodes = { | |
400: "Bad Request", | |
401: "Unauthorized", | |
402: "Payment Required", | |
403: "Forbidden", | |
404: "Not Found", | |
405: "Method Not Allowed", | |
406: "Not Acceptable", | |
407: "Proxy Authentication Required", | |
408: "Request Timeout", | |
409: "Conflict", | |
410: "Gone", | |
411: "Length Required", | |
412: "Precondition Failed", | |
413: "Request Entity Too Large", | |
414: "Request-URI Too Long", | |
415: "Unsupported Media Type", | |
416: "Requested Range Not Satisfiable", | |
417: "Expectation Failed", | |
420: "Enhance Your Calm", | |
422: "Unprocessable Entity", | |
423: "Locked", | |
424: "Failed Dependency", | |
425: "Unordered Collection", | |
426: "Upgrade Required", | |
428: "Precondition Required", | |
429: "Too Many Requests", | |
431: "Request Header Fields Too Large", | |
444: "No Response", | |
449: "Retry With", | |
499: "Client Closed Request", | |
500: "Internal Server Error", | |
501: "Not Implemented", | |
502: "Bad Gateway", | |
503: "Service Unavailable", | |
504: "Gateway Timeout", | |
505: "HTTP Version Not Supported", | |
506: "Variant Also Negotiates", | |
507: "Insufficient Storage", | |
508: "Loop Detected", | |
509: "Bandwidth Limit Exceeded", | |
510: "Not Extended", | |
511: "Network Authentication Required" | |
}; | |
function HTTPError(status) { | |
this.message = { | |
status: status, | |
message: statusCodes[status] | |
}; | |
this.stack = (new Error()).stack; | |
} | |
HTTPError.prototype = Object.create(Error.prototype); | |
HTTPError.prototype.name = 'HTTPError'; | |
module.exports = HTTPError; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment