client-oauth2
Advanced tools
Comparing version 0.0.4 to 0.1.0
(function (root) { | ||
var isBrowser = typeof window === 'object'; | ||
var hasBuffer = typeof Buffer === 'function'; | ||
var _hasOwnProperty = Object.prototype.hasOwnProperty; | ||
var btoa = typeof Buffer === 'function' ? bufferBtoa : root.btoa; | ||
var btoa = hasBuffer ? btoaBuffer : root.btoa; | ||
var popsicle = isBrowser ? root.popsicle : require('popsicle'); | ||
@@ -89,3 +92,3 @@ /** | ||
*/ | ||
function bufferBtoa (string) { | ||
function btoaBuffer (string) { | ||
return new Buffer(string).toString('base64'); | ||
@@ -134,54 +137,2 @@ } | ||
/** | ||
* Attempt (and fix) URI component encoding. | ||
* | ||
* @param {String} str | ||
* @return {String} | ||
*/ | ||
function encodeComponent (str) { | ||
return encodeURIComponent(str) | ||
.replace(/[!'()]/g, root.escape) | ||
.replace(/\*/g, '%2A'); | ||
} | ||
/** | ||
* Attempt URI component decoding. | ||
* | ||
* @param {String} str | ||
* @return {String} | ||
*/ | ||
function decodeComponent (str) { | ||
return decodeURIComponent(str); | ||
} | ||
/** | ||
* Convert an object into a query string. | ||
* | ||
* @param {Object} obj | ||
* @param {String} sep | ||
* @param {String} eq | ||
* @return {String} | ||
*/ | ||
function uriEncode (obj, sep, eq) { | ||
var params = []; | ||
eq = eq || '='; | ||
sep = sep || '&'; | ||
Object.keys(obj).forEach(function (key) { | ||
var value = obj[key]; | ||
var keyStr = encodeComponent(key) + eq; | ||
if (Array.isArray(value)) { | ||
for (var i = 0; i < value.length; i++) { | ||
params.push(keyStr + encodeComponent(value[i])); | ||
} | ||
} else if (value != null) { | ||
params.push(keyStr + encodeComponent(value)); | ||
} | ||
}); | ||
return params.join(sep); | ||
} | ||
/** | ||
* Convert a query string into an object. | ||
@@ -194,3 +145,3 @@ * | ||
*/ | ||
function uriDecode (qs, sep, eq) { | ||
function decodeQuery (qs, sep, eq) { | ||
eq = eq || '='; | ||
@@ -202,3 +153,3 @@ sep = sep || '&'; | ||
var maxKeys = 1000; | ||
var len = qs.length > maxKeys ? maxKeys : qs.length; | ||
var len = Math.min(qs.length, maxKeys); | ||
@@ -215,4 +166,4 @@ for (var i = 0; i < len; i++) { | ||
key = decodeComponent(key); | ||
value = decodeComponent(value); | ||
key = decodeURIComponent(key); | ||
value = decodeURIComponent(value); | ||
@@ -247,25 +198,17 @@ if (!_hasOwnProperty.call(obj, key)) { | ||
/** | ||
* Retrieve all the HTTP response headers for an XMLHttpRequest instance. | ||
* Handle the authentication response object. | ||
* | ||
* @param {XMLHttpRequest} xhr | ||
* @return {Object} | ||
* @param {Object} res | ||
* @return {Promise} | ||
*/ | ||
function getAllReponseHeaders (xhr) { | ||
var headers = {}; | ||
function handleAuthResponse (res) { | ||
var data = res.body; | ||
var err = getAuthError(data); | ||
// Split all header lines and iterate. | ||
xhr.getAllResponseHeaders().split('\n').forEach(function (header) { | ||
var index = header.indexOf(':'); | ||
// If the response contains an error, reject the refresh token. | ||
if (err) { | ||
return Promise.reject(err); | ||
} | ||
if (index === -1) { | ||
return; | ||
} | ||
var name = header.substr(0, index).toLowerCase(); | ||
var value = header.substr(index + 1).trim(); | ||
headers[name] = value; | ||
}); | ||
return headers; | ||
return data; | ||
} | ||
@@ -281,3 +224,3 @@ | ||
if (!Array.isArray(scopes)) { | ||
return scopes == null ? null : String(scopes); | ||
return scopes == null ? '' : String(scopes); | ||
} | ||
@@ -289,2 +232,32 @@ | ||
/** | ||
* Create a request uri based on an options object and token type. | ||
* | ||
* @param {Object} options | ||
* @param {String} tokenType | ||
* @return {String} | ||
*/ | ||
function createUri (options, tokenType) { | ||
// Check the required parameters have been set. | ||
expects(options, [ | ||
'clientId', | ||
'redirectUri', | ||
'authorizationUri' | ||
]); | ||
var clientId = encodeURIComponent(options.clientId); | ||
var redirectUri = encodeURIComponent(options.redirectUri); | ||
var scopes = encodeURIComponent(sanitizeScope(options.scopes)); | ||
var uri = options.authorizationUri + '?client_id=' + clientId + | ||
'&redirect_uri=' + redirectUri + | ||
'&scope=' + scopes + | ||
'&response_type=' + tokenType; | ||
if (options.state) { | ||
uri += '&state=' + encodeURIComponent(options.state); | ||
} | ||
return uri; | ||
} | ||
/** | ||
* Construct an object that can handle the multiple OAuth 2.0 flows. | ||
@@ -320,7 +293,9 @@ * | ||
ClientOAuth2.prototype.createToken = function (access, refresh, type, data) { | ||
return new ClientOAuth2Token(this, assign({}, data, { | ||
data = assign({}, data, { | ||
access_token: access, | ||
refresh_token: refresh, | ||
token_type: type | ||
})); | ||
}); | ||
return new ClientOAuth2Token(this, data); | ||
}; | ||
@@ -332,126 +307,23 @@ | ||
* | ||
* @param {Object} options | ||
* @param {Function} done | ||
* @param {Object} options | ||
* @return {Promise} | ||
*/ | ||
ClientOAuth2.prototype._request = function (options, done) { | ||
return this.request(options, function (err, res) { | ||
if (err) { | ||
return done(err); | ||
} | ||
ClientOAuth2.prototype._request = function (options) { | ||
return this.request(options) | ||
.then(function (res) { | ||
if (res.status < 200 || res.status >= 300) { | ||
var err = new Error('HTTP status ' + res.status); | ||
err.status = res.status; | ||
return Promise.reject(err); | ||
} | ||
// Check the response status and fail. | ||
if (res.status && Math.floor(res.status / 100) !== 2) { | ||
err = new Error('HTTP Status ' + res.status); | ||
err.status = res.status; | ||
return done(err); | ||
} | ||
// Support already parsed responses in case of custom body parsing. | ||
if (typeof res.body !== 'string') { | ||
return done(null, res.body); | ||
} | ||
// Attempt to parse as JSON, falling back to parsing as a query string. | ||
try { | ||
done(null, JSON.parse(res.body)); | ||
} catch (e) { | ||
done(null, uriDecode(res.body)); | ||
} | ||
}); | ||
return res; | ||
}); | ||
}; | ||
if (typeof window !== 'undefined') { | ||
/** | ||
* Make a HTTP request using XMLHttpRequest. | ||
* | ||
* @param {Object} options | ||
* @param {Function} done | ||
*/ | ||
ClientOAuth2.prototype.request = function (options, done) { | ||
var xhr = new root.XMLHttpRequest(); | ||
var headers = options.headers || {}; | ||
/** | ||
* Set `popsicle` as the default request method. | ||
*/ | ||
ClientOAuth2.prototype.request = popsicle; | ||
// Open the request to the uri and method. | ||
xhr.open(options.method, options.uri); | ||
// When the request has loaded, attempt to automatically parse the body. | ||
xhr.onload = function () { | ||
return done(null, { | ||
raw: xhr, | ||
status: xhr.status, | ||
headers: getAllReponseHeaders(xhr), | ||
body: xhr.responseText | ||
}); | ||
}; | ||
// Catch request errors. | ||
xhr.onerror = xhr.onabort = function () { | ||
return done(new Error(xhr.statusText || 'XHR aborted')); | ||
}; | ||
// Set all request headers. | ||
Object.keys(headers).forEach(function (header) { | ||
xhr.setRequestHeader(header, headers[header]); | ||
}); | ||
// Make the request with the body. | ||
xhr.send(options.body); | ||
}; | ||
} else { | ||
var url = require('url'); | ||
var http = require('http'); | ||
var https = require('https'); | ||
/** | ||
* Make a request using the built-in node http library. | ||
* | ||
* @param {Object} options | ||
* @param {Function} done | ||
*/ | ||
ClientOAuth2.prototype.request = function (options, done) { | ||
var lib = http; | ||
var reqOpts = url.parse(options.uri); | ||
// If the protocol is over https, switch request library. | ||
if (reqOpts.protocol === 'https:') { | ||
lib = https; | ||
} | ||
// Alias request options. | ||
reqOpts.method = options.method; | ||
reqOpts.headers = options.headers; | ||
// Send the http request and listen for the response to finish. | ||
var req = lib.request(reqOpts, function (res) { | ||
var data = ''; | ||
// Callback to `done` if a response error occurs. | ||
res.on('error', done); | ||
// Concat all the data chunks into a string. | ||
res.on('data', function (chunk) { | ||
data += chunk; | ||
}); | ||
// When the response is finished, attempt to parse the data string. | ||
res.on('end', function () { | ||
return done(null, { | ||
raw: res, | ||
status: res.statusCode, | ||
headers: res.headers, | ||
body: data | ||
}); | ||
}); | ||
}); | ||
// Callback to `done` if a request error occurs. | ||
req.on('error', done); | ||
// Send the body and make the request. | ||
req.write(options.body); | ||
req.end(); | ||
}; | ||
} | ||
/** | ||
@@ -519,7 +391,7 @@ * General purpose client token generator. | ||
* | ||
* @param {Object} opts | ||
* @param {Function} done | ||
* @param {Object} opts | ||
* @return {Promise} | ||
*/ | ||
ClientOAuth2Token.prototype.request = function (opts, done) { | ||
return this.client.request(this.sign(opts), done); | ||
ClientOAuth2Token.prototype.request = function (opts) { | ||
return this.client.request(this.sign(opts)); | ||
}; | ||
@@ -530,5 +402,5 @@ | ||
* | ||
* @param {Function} done | ||
* @return {Promise} | ||
*/ | ||
ClientOAuth2Token.prototype.refresh = function (done) { | ||
ClientOAuth2Token.prototype.refresh = function () { | ||
var self = this; | ||
@@ -538,3 +410,3 @@ var options = this.client.options; | ||
if (!this.refreshToken) { | ||
return done(new Error('No refresh token set')); | ||
return Promise.reject(new Error('No refresh token set')); | ||
} | ||
@@ -545,3 +417,3 @@ | ||
return this.client._request({ | ||
uri: options.accessTokenUri, | ||
url: options.accessTokenUri, | ||
method: 'POST', | ||
@@ -553,18 +425,15 @@ headers: { | ||
}, | ||
body: uriEncode({ | ||
body: { | ||
refresh_token: this.refreshToken, | ||
grant_type: 'refresh_token' | ||
}) | ||
}, function (err, data) { | ||
// If an error exists or the data contains an error, return `done`. | ||
if (err || (err = getAuthError(data))) { | ||
return done(err); | ||
} | ||
}) | ||
.then(handleAuthResponse) | ||
.then(function (data) { | ||
// Update stored tokens on the current instance. | ||
self.accessToken = data.access_token; | ||
self.refreshToken = data.refresh_token; | ||
// Update stored tokens on the current instance. | ||
self.accessToken = data.access_token; | ||
self.refreshToken = data.refresh_token; | ||
return done(null, self); | ||
}); | ||
return self; | ||
}); | ||
}; | ||
@@ -599,7 +468,7 @@ | ||
* | ||
* @param {String} username | ||
* @param {String} password | ||
* @param {Function} done | ||
* @param {String} username | ||
* @param {String} password | ||
* @return {Promise} | ||
*/ | ||
OwnerFlow.prototype.getToken = function (username, password, done) { | ||
OwnerFlow.prototype.getToken = function (username, password) { | ||
var self = this; | ||
@@ -610,3 +479,3 @@ var options = this.client.options; | ||
return this.client._request({ | ||
uri: options.accessTokenUri, | ||
url: options.accessTokenUri, | ||
method: 'POST', | ||
@@ -618,3 +487,3 @@ headers: { | ||
}, | ||
body: uriEncode({ | ||
body: { | ||
scope: sanitizeScope(options.scopes), | ||
@@ -624,11 +493,8 @@ username: username, | ||
grant_type: 'password' | ||
}) | ||
}, function (err, data) { | ||
// If an error exists or the data contains an error, return `done`. | ||
if (err || (err = getAuthError(data))) { | ||
return done(err); | ||
} | ||
return done(null, new ClientOAuth2Token(self, data)); | ||
}); | ||
}) | ||
.then(handleAuthResponse) | ||
.then(function (data) { | ||
return new ClientOAuth2Token(self, data); | ||
}); | ||
}; | ||
@@ -656,16 +522,3 @@ | ||
// Check the parameters have been set. | ||
expects(options, [ | ||
'clientId', | ||
'redirectUri', | ||
'authorizationUri' | ||
]); | ||
return options.authorizationUri + '?' + uriEncode({ | ||
state: options.state, | ||
scope: sanitizeScope(options.scopes), | ||
client_id: options.clientId, | ||
redirect_uri: options.redirectUri, | ||
response_type: 'token' | ||
}); | ||
return createUri(options, 'token'); | ||
}; | ||
@@ -676,50 +529,55 @@ | ||
* | ||
* @param {String} uri | ||
* @param {String} [state] | ||
* @param {Function} done | ||
* @param {String} uri | ||
* @param {String} [state] | ||
* @return {Promise} | ||
*/ | ||
TokenFlow.prototype.getToken = function (uri, state, done) { | ||
TokenFlow.prototype.getToken = function (uri, state) { | ||
var data = {}; | ||
var options = this.client.options; | ||
var err; | ||
// State is an optional pass in. | ||
if (typeof state === 'function') { | ||
done = state; | ||
state = null; | ||
} | ||
// Make sure the uri matches our expected redirect uri. | ||
if (uri.substr(0, options.redirectUri.length) !== options.redirectUri) { | ||
return done(new Error('Invalid uri (should to match redirect): ' + uri)); | ||
return Promise.reject(new Error('Should match redirect uri: ' + uri)); | ||
} | ||
var queryString = uri.replace(/^[^\?]*|\#.*$/g, '').substr(1); | ||
var fragmentString = uri.replace(/^[^\#]*/, '').substr(1); | ||
var queryIndex = uri.indexOf('?'); | ||
var fragmentIndex = uri.indexOf('#'); | ||
// Check whether a query string is present in the uri. | ||
if (!queryString && !fragmentString) { | ||
return done(new Error('Unable to process uri: ' + uri)); | ||
// If no query string or fragment exists, we won't be able to parse | ||
// any useful information from the uri. | ||
if (queryIndex === -1 && fragmentIndex === -1) { | ||
return Promise.reject(new Error('Unable to process uri: ' + uri)); | ||
} | ||
// Merge the fragment with the the query string. This is because, at least, | ||
// Instagram has a bug where the OAuth 2.0 state is being passed back as | ||
// part of the query string instead of the fragment. For example: | ||
// "?state=123#access_token=abc" | ||
var data = assign( | ||
queryString ? uriDecode(queryString) : {}, | ||
fragmentString ? uriDecode(fragmentString) : {} | ||
); | ||
// Extract the query string and parse. This is needed because Instagram | ||
// has a bug where the OAuth 2.0 state is passed back via the query string. | ||
if (queryIndex > -1 && queryIndex < fragmentIndex) { | ||
var endIndex = fragmentIndex === -1 ? uri.length : fragmentIndex; | ||
var query = uri.slice(queryIndex + 1, endIndex); | ||
assign(data, decodeQuery(query)); | ||
} | ||
// Extract data from the uri fragment, which is more important than the | ||
// query string which shouldn't hold any information. | ||
if (fragmentIndex > -1) { | ||
var fragment = uri.substr(fragmentIndex + 1); | ||
assign(data, decodeQuery(fragment)); | ||
} | ||
var err = getAuthError(data); | ||
// Check if the query string was populated with a known error. | ||
if (err = getAuthError(data)) { | ||
return done(err); | ||
if (err) { | ||
return Promise.reject(err); | ||
} | ||
// Check whether the state is correct. | ||
if (state && data.state !== state) { | ||
return done(new Error('Invalid state:' + data.state)); | ||
// Check whether the state matches. | ||
if (state != null && data.state !== state) { | ||
return Promise.reject(new Error('Invalid state: ' + data.state)); | ||
} | ||
// Initalize a new token and return. | ||
return done(null, new ClientOAuth2Token(this, data)); | ||
return Promise.resolve(new ClientOAuth2Token(this, data)); | ||
}; | ||
@@ -741,14 +599,8 @@ | ||
* | ||
* @param {Object} [options] | ||
* @param {Function} done | ||
* @param {Object} [options] | ||
* @return {Promise} | ||
*/ | ||
CredentialsFlow.prototype.getToken = function (options, done) { | ||
CredentialsFlow.prototype.getToken = function (options) { | ||
var self = this; | ||
// Allow the options argument to be omitted. | ||
if (typeof options === 'function') { | ||
done = options; | ||
options = null; | ||
} | ||
options = assign({}, this.client.options, options); | ||
@@ -766,3 +618,3 @@ | ||
return this.client._request({ | ||
uri: options.accessTokenUri, | ||
url: options.accessTokenUri, | ||
method: 'POST', | ||
@@ -774,14 +626,11 @@ headers: { | ||
}, | ||
body: uriEncode({ | ||
body: { | ||
scope: sanitizeScope(options.scopes), | ||
grant_type: 'client_credentials' | ||
}) | ||
}, function (err, data) { | ||
// If an error exists or the data contains an error, return `done`. | ||
if (err || (err = getAuthError(data))) { | ||
return done(err); | ||
} | ||
return done(null, new ClientOAuth2Token(self, data)); | ||
}); | ||
}) | ||
.then(handleAuthResponse) | ||
.then(function (data) { | ||
return new ClientOAuth2Token(self, data); | ||
}); | ||
}; | ||
@@ -808,16 +657,3 @@ | ||
// Check the parameters have been set. | ||
expects(options, [ | ||
'clientId', | ||
'redirectUri', | ||
'authorizationUri' | ||
]); | ||
return options.authorizationUri + '?' + uriEncode({ | ||
state: options.state, | ||
scope: sanitizeScope(options.scopes), | ||
client_id: options.clientId, | ||
redirect_uri: options.redirectUri, | ||
response_type: 'code' | ||
}); | ||
return createUri(options, 'code'); | ||
}; | ||
@@ -829,17 +665,10 @@ | ||
* | ||
* @param {String} uri | ||
* @param {String} [state] | ||
* @param {Function} done | ||
* @param {String} uri | ||
* @param {String} [state] | ||
* @return {Promise} | ||
*/ | ||
CodeFlow.prototype.getToken = function (uri, state, done) { | ||
CodeFlow.prototype.getToken = function (uri, state) { | ||
var self = this; | ||
var options = this.client.options; | ||
var err; | ||
// State is an optional pass in. | ||
if (typeof state === 'function') { | ||
done = state; | ||
state = null; | ||
} | ||
expects(options, [ | ||
@@ -854,32 +683,31 @@ 'clientId', | ||
if (uri.substr(0, options.redirectUri.length) !== options.redirectUri) { | ||
return done(new Error('Invalid uri (should to match redirect): ' + uri)); | ||
return Promise.reject(new Error('Should match redirect uri: ' + uri)); | ||
} | ||
// Extract the query string from the url. | ||
var queryString = uri.replace(/^[^\?]*|\#.*$/g, '').substr(1); | ||
var queryIndex = uri.indexOf('?'); | ||
var fragmentIndex = uri.indexOf('#'); | ||
// Check whether a query string is present in the uri. | ||
if (!queryString) { | ||
return done(new Error('Unable to process uri: ' + uri)); | ||
if (queryIndex === -1) { | ||
return Promise.reject(new Error('Unable to process uri: ' + uri)); | ||
} | ||
var query = uriDecode(queryString); | ||
var endIndex = fragmentIndex === -1 ? uri.length : fragmentIndex; | ||
var data = decodeQuery(uri.slice(queryIndex + 1, endIndex)); | ||
var err = getAuthError(data); | ||
// Check if the query string was populated with a known error. | ||
if (err = getAuthError(query)) { | ||
return done(err); | ||
if (err) { | ||
return Promise.reject(err); | ||
} | ||
// Check whether the state is correct. | ||
if (state && query.state !== state) { | ||
return done(new Error('Invalid state:' + query.state)); | ||
if (state && data.state !== state) { | ||
return Promise.reject(new Error('Invalid state:' + data.state)); | ||
} | ||
// Check whether the response code is set. | ||
if (!query.code) { | ||
return done(new Error('Missing code, unable to request token')); | ||
if (!data.code) { | ||
return Promise.reject(new Error('Missing code, unable to request token')); | ||
} | ||
return this.client._request({ | ||
uri: options.accessTokenUri, | ||
url: options.accessTokenUri, | ||
method: 'POST', | ||
@@ -890,4 +718,4 @@ headers: { | ||
}, | ||
body: uriEncode({ | ||
code: query.code, | ||
body: { | ||
code: data.code, | ||
grant_type: 'authorization_code', | ||
@@ -897,11 +725,8 @@ redirect_uri: options.redirectUri, | ||
client_secret: options.clientSecret | ||
}) | ||
}, function (err, data) { | ||
// If an error exists or the data contains an error, return `done`. | ||
if (err || (err = getAuthError(data))) { | ||
return done(err); | ||
} | ||
return done(null, new ClientOAuth2Token(self, data)); | ||
}); | ||
}) | ||
.then(handleAuthResponse) | ||
.then(function (data) { | ||
return new ClientOAuth2Token(self, data); | ||
}); | ||
}; | ||
@@ -908,0 +733,0 @@ |
{ | ||
"name": "client-oauth2", | ||
"version": "0.0.4", | ||
"description": "A no-dependency library for executing OAuth 2.0 flows.", | ||
"version": "0.1.0", | ||
"description": "Straight-forward library for executing OAuth 2.0 flows and making API requests.", | ||
"main": "client-oauth2.js", | ||
@@ -26,5 +26,6 @@ "scripts": { | ||
"chai": "^1.9.1", | ||
"es6-promise": "^2.0.0", | ||
"gulp": "^3.8.6", | ||
"gulp-jshint": "^1.8.4", | ||
"gulp-mocha": "^1.1.0", | ||
"gulp-mocha": "^2.0.0", | ||
"is-travis": "^1.0.0", | ||
@@ -38,6 +39,9 @@ "karma": "^0.12.23", | ||
"karma-sinon-chai": "^0.2.0", | ||
"mocha": "^1.21.3", | ||
"nock": "^0.46.0", | ||
"mocha": "^2.0.1", | ||
"nock": "^0.51.0", | ||
"require-dir": "^0.1.0" | ||
}, | ||
"dependencies": { | ||
"popsicle": "0.0.2" | ||
} | ||
} |
@@ -6,4 +6,6 @@ # Client OAuth 2.0 | ||
A no-dependencies library for executing OAuth 2.0 grant flows and user requests in node and on the browser. | ||
Straight-forward library for executing OAuth 2.0 grant flows and making API requests in node and on the browser. | ||
**Please note: This module uses [Popsicle](https://github.com/blakeembrey/popsicle) to make API requests. Promises must be supported or polyfilled on all target environments.** | ||
## Installation | ||
@@ -36,13 +38,14 @@ | ||
// Refresh the users credentials and save the updated access token. | ||
token.refresh(cb); | ||
token.refresh().then(updateToken); | ||
token.request({ | ||
method: 'get', | ||
uri: 'https://api.github.com/users' | ||
}, function (err, res) { | ||
console.log(res); //=> { raw: [Object], body: '...', status: 200, headers: { ... } } | ||
url: 'https://api.github.com/users' | ||
}) | ||
.then(function (res) { | ||
console.log(res); //=> { raw: [Object], body: '...', status: 200, headers: { ... } } | ||
}) | ||
``` | ||
You can even override the request mechanism if you need a custom implementation not supported by setting `githubAuth.request = function (opts, cb) {}`. You will need to take care to ensure the custom request mechanism supports the correct input and output object though. | ||
You can override the request mechanism if you need a custom implementation by setting `githubAuth.request = function (opts) { return new Promise(...); }`. You will need to make sure that the custom request mechanism supports the correct input and output objects. | ||
@@ -54,3 +57,3 @@ ### [Authorization Code Grant](http://tools.ietf.org/html/rfc6749#section-4.1) | ||
1. Redirect user to `githubAuth.code.getUri()`. | ||
2. Parse response uri and get token using `githubAuth.code.getToken(uri, cb)`. | ||
2. Parse response uri and get token using `githubAuth.code.getToken(uri)`. | ||
@@ -68,17 +71,20 @@ ```javascript | ||
app.get('/auth/github/callback', function (req, res) { | ||
githubAuth.code.getToken(req.url, function (err, user) { | ||
// Refresh the users access token. | ||
user.refresh(function (err, updatedUser) { | ||
console.log(updatedUser === user); //=> true | ||
}); | ||
githubAuth.code.getToken(req.url) | ||
.then(function (user) { | ||
console.log(user); //=> { accessToken: '...', tokenType: 'bearer', ... } | ||
// Sign requests on behalf of the user. | ||
user.sign({ | ||
method: 'get', | ||
uri: 'http://example.com' | ||
// Refresh the current users access token. | ||
user.refresh().then(function (updatedUser) { | ||
console.log(updatedUser === user); //=> true | ||
}); | ||
// Sign API requests on behalf of the current user. | ||
user.sign({ | ||
method: 'get', | ||
url: 'http://example.com' | ||
}); | ||
// We should store the token into a database. | ||
return res.send(user.accessToken); | ||
}); | ||
// Should store this into the database. | ||
return res.send(user.accessToken); | ||
}); | ||
}); | ||
@@ -92,16 +98,18 @@ ``` | ||
1. Redirect user to `githubAuth.token.getUri()`. | ||
2. Parse response uri for the access token using `githubAuth.token.getToken(uri, cb)`. | ||
2. Parse response uri for the access token using `githubAuth.token.getToken(uri)`. | ||
```javascript | ||
window.oauth2Callback = function (uri) { | ||
githubAuth.token.getToken(uri, function (err, user) { | ||
// Log the instance of our users token. | ||
console.log(user); | ||
githubAuth.token.getToken(uri) | ||
.then(function (user) { | ||
console.log(user); //=> { accessToken: '...', tokenType: 'bearer', ... } | ||
// Make a HTTP request to the github API for the user. | ||
user.request({ | ||
method: 'get', | ||
uri: 'https://api.github.com/user' | ||
// Make a request to the github API for the current user. | ||
user.request({ | ||
method: 'get', | ||
url: 'https://api.github.com/user' | ||
}).then(function (res) { | ||
console.log(res); //=> { body: { ... }, status: 200, headers: { ... } } | ||
}); | ||
}); | ||
}); | ||
}; | ||
@@ -117,4 +125,11 @@ | ||
1. Make a direct request for tokens on behalf of the user using `githubAuth.owner.getToken(username, password, cb)`. | ||
1. Make a direct request for the access token on behalf of the user using `githubAuth.owner.getToken(username, password)`. | ||
```javascript | ||
githubAuth.owner.getToken('blakeembrey', 'hunter2') | ||
.then(function (user) { | ||
console.log(user); //=> { accessToken: '...', tokenType: 'bearer', ... } | ||
}); | ||
``` | ||
### [Client Credentials Grant](http://tools.ietf.org/html/rfc6749#section-4.4) | ||
@@ -124,4 +139,11 @@ | ||
1. Get the access token directly for the application by using `githubAuth.credentials.getToken(cb)`. | ||
1. Get the access token for the application by using `githubAuth.credentials.getToken()`. | ||
```javascript | ||
githubAuth.credentials.getToken() | ||
.then(function (user) { | ||
console.log(user); //=> { accessToken: '...', tokenType: 'bearer', ... } | ||
}); | ||
``` | ||
## License | ||
@@ -128,0 +150,0 @@ |
@@ -40,2 +40,5 @@ var path = require('path'); | ||
files: [ | ||
'node_modules/es6-promise/dist/es6-promise.js', | ||
'test/support/globals.js', | ||
'node_modules/popsicle/popsicle.js', | ||
'client-oauth2.js', | ||
@@ -42,0 +45,0 @@ 'test/browser/**/*.js' |
@@ -17,3 +17,6 @@ var join = require('path').join; | ||
gulp.task('test:node', function () { | ||
return gulp.src('test/node/**/*.js', { read: false }) | ||
return gulp.src([ | ||
'test/support/globals.js', | ||
'test/node/**/*.js' | ||
], { read: false }) | ||
.pipe(mocha({ reporter: 'spec' })); | ||
@@ -20,0 +23,0 @@ }); |
@@ -15,6 +15,5 @@ describe('code', function () { | ||
expect(githubAuth.code.getUri()).to.equal( | ||
'https://github.com/login/oauth/authorize?scope=notifications&' + | ||
'client_id=abc&' + | ||
'https://github.com/login/oauth/authorize?client_id=abc&' + | ||
'redirect_uri=http%3A%2F%2Fexample.com%2Fauth%2Fcallback&' + | ||
'response_type=code' | ||
'scope=notifications&response_type=code' | ||
); | ||
@@ -51,15 +50,14 @@ }); | ||
it('should request the token', function (done) { | ||
it('should request the token', function () { | ||
var uri = 'http://example.com/auth/callback?code=fbe55d970377e0686746&' + | ||
'state=7076840850058943'; | ||
githubAuth.code.getToken(uri, function (err, user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
return done(err); | ||
}); | ||
return githubAuth.code.getToken(uri) | ||
.then(function (user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -47,12 +47,11 @@ describe('credentials', function () { | ||
it('should request the token', function (done) { | ||
githubAuth.credentials.getToken(function (err, user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
return done(err); | ||
}); | ||
it('should request the token', function () { | ||
return githubAuth.credentials.getToken() | ||
.then(function (user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -26,3 +26,3 @@ describe('owner', function () { | ||
expect(xhr.requestBody).to.equal( | ||
'username=blakeembrey&password=hunter2&grant_type=password' | ||
'scope=&username=blakeembrey&password=hunter2&grant_type=password' | ||
); | ||
@@ -47,12 +47,11 @@ expect(xhr.requestHeaders.Authorization).to.equal(authHeader); | ||
it('should get the token on behalf of the user', function (done) { | ||
githubAuth.owner.getToken('blakeembrey', 'hunter2', function (err, user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
return done(err); | ||
}); | ||
it('should get the token on behalf of the user', function () { | ||
return githubAuth.owner.getToken('blakeembrey', 'hunter2') | ||
.then(function (user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -15,6 +15,5 @@ describe('token', function () { | ||
expect(githubAuth.token.getUri()).to.equal( | ||
'https://github.com/login/oauth/authorize?scope=notifications&' + | ||
'client_id=abc&' + | ||
'https://github.com/login/oauth/authorize?client_id=abc&' + | ||
'redirect_uri=http%3A%2F%2Fexample.com%2Fauth%2Fcallback&' + | ||
'response_type=token' | ||
'scope=notifications&response_type=token' | ||
); | ||
@@ -26,15 +25,17 @@ }); | ||
var accessToken = '4430eb16f4f6577c0f3a15fb6127cbf828a8e403'; | ||
var refreshToken = '4430eb16f4f6577c0f3a15fb6127cbf828a8e404'; | ||
it('should parse the token from the response', function (done) { | ||
var uri = 'http://example.com/auth/callback#access_token=' + accessToken; | ||
it('should parse the token from the response', function () { | ||
var uri = 'http://example.com/auth/callback?' + | ||
'refresh_token=' + refreshToken + '#access_token=' + accessToken; | ||
githubAuth.token.getToken(uri, function (err, user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
return done(err); | ||
}); | ||
return githubAuth.token.getToken(uri) | ||
.then(function (user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.refreshToken).to.equal(refreshToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -1,2 +0,2 @@ | ||
describe('user token instance', function () { | ||
describe('user', function () { | ||
var githubAuth = new ClientOAuth2({ | ||
@@ -56,16 +56,15 @@ clientId: 'abc', | ||
it('should make a request on behalf of the user', function (done) { | ||
it('should make a request on behalf of the user', function () { | ||
return token.request({ | ||
method: 'GET', | ||
uri: 'http://api.github.com/user' | ||
}, function (err, response) { | ||
expect(response.raw).to.exist; | ||
expect(response.status).to.equal(200); | ||
expect(response.body).to.equal('{"username":"blakeembrey"}'); | ||
expect(response.headers).to.deep.equal({ | ||
'content-type': 'application/json' | ||
url: 'http://api.github.com/user' | ||
}) | ||
.then(function (res) { | ||
expect(res.raw).to.exist; | ||
expect(res.status).to.equal(200); | ||
expect(res.body).to.deep.equal({ username: 'blakeembrey' }); | ||
expect(res.headers).to.deep.equal({ | ||
'content-type': 'application/json' | ||
}); | ||
}); | ||
return done(err); | ||
}); | ||
}); | ||
@@ -107,12 +106,11 @@ }); | ||
it('should make a request to get a new access token', function (done) { | ||
return currentToken.refresh(function (err, token) { | ||
expect(token).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(token.accessToken).to.equal('def456token'); | ||
expect(token.tokenType).to.equal('bearer'); | ||
return done(err); | ||
}); | ||
it('should make a request to get a new access token', function () { | ||
return currentToken.refresh() | ||
.then(function (token) { | ||
expect(token).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(token.accessToken).to.equal('def456token'); | ||
expect(token.tokenType).to.equal('bearer'); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -19,6 +19,5 @@ var nock = require('nock'); | ||
expect(githubAuth.code.getUri()).to.equal( | ||
'https://github.com/login/oauth/authorize?scope=notifications&' + | ||
'client_id=abc&' + | ||
'https://github.com/login/oauth/authorize?client_id=abc&' + | ||
'redirect_uri=http%3A%2F%2Fexample.com%2Fauth%2Fcallback&' + | ||
'response_type=code' | ||
'scope=notifications&response_type=code' | ||
); | ||
@@ -41,15 +40,14 @@ }); | ||
it('should request the token', function (done) { | ||
it('should request the token', function () { | ||
var uri = 'http://example.com/auth/callback?code=fbe55d970377e0686746&' + | ||
'state=7076840850058943'; | ||
githubAuth.code.getToken(uri, function (err, user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
return done(err); | ||
}); | ||
return githubAuth.code.getToken(uri) | ||
.then(function (user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -37,12 +37,11 @@ var nock = require('nock'); | ||
it('should request the token', function (done) { | ||
githubAuth.credentials.getToken(function (err, user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
return done(err); | ||
}); | ||
it('should request the token', function () { | ||
return githubAuth.credentials.getToken() | ||
.then(function (user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -27,3 +27,3 @@ var nock = require('nock'); | ||
'/login/oauth/access_token', | ||
'username=blakeembrey&password=hunter2&grant_type=password' | ||
'scope=&username=blakeembrey&password=hunter2&grant_type=password' | ||
) | ||
@@ -37,12 +37,11 @@ .reply(200, { | ||
it('should get the token on behalf of the user', function (done) { | ||
githubAuth.owner.getToken('blakeembrey', 'hunter2', function (err, user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
return done(err); | ||
}); | ||
it('should get the token on behalf of the user', function () { | ||
return githubAuth.owner.getToken('blakeembrey', 'hunter2') | ||
.then(function (user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -18,6 +18,5 @@ var expect = require('chai').expect; | ||
expect(githubAuth.token.getUri()).to.equal( | ||
'https://github.com/login/oauth/authorize?scope=notifications&' + | ||
'client_id=abc&' + | ||
'https://github.com/login/oauth/authorize?client_id=abc&' + | ||
'redirect_uri=http%3A%2F%2Fexample.com%2Fauth%2Fcallback&' + | ||
'response_type=token' | ||
'scope=notifications&response_type=token' | ||
); | ||
@@ -29,15 +28,17 @@ }); | ||
var accessToken = '4430eb16f4f6577c0f3a15fb6127cbf828a8e403'; | ||
var refreshToken = '4430eb16f4f6577c0f3a15fb6127cbf828a8e404'; | ||
it('should parse the token from the response', function (done) { | ||
var uri = 'http://example.com/auth/callback#access_token=' + accessToken; | ||
it('should parse the token from the response', function () { | ||
var uri = 'http://example.com/auth/callback?' + | ||
'refresh_token=' + refreshToken + '#access_token=' + accessToken; | ||
githubAuth.token.getToken(uri, function (err, user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
return done(err); | ||
}); | ||
return githubAuth.token.getToken(uri) | ||
.then(function (user) { | ||
expect(user).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(user.accessToken).to.equal(accessToken); | ||
expect(user.refreshToken).to.equal(refreshToken); | ||
expect(user.tokenType).to.equal('bearer'); | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -5,3 +5,3 @@ var nock = require('nock'); | ||
describe('user token instance', function () { | ||
describe('user', function () { | ||
var githubAuth = new ClientOAuth2({ | ||
@@ -47,16 +47,15 @@ clientId: 'abc', | ||
it('should make a request on behalf of the user', function (done) { | ||
it('should make a request on behalf of the user', function () { | ||
return token.request({ | ||
method: 'GET', | ||
uri: 'http://api.github.com/user' | ||
}, function (err, response) { | ||
expect(response.raw).to.exist; | ||
expect(response.status).to.equal(200); | ||
expect(response.body).to.equal('{"username":"blakeembrey"}'); | ||
expect(response.headers).to.deep.equal({ | ||
'content-type': 'application/json' | ||
url: 'http://api.github.com/user' | ||
}) | ||
.then(function (res) { | ||
expect(res.raw).to.exist; | ||
expect(res.status).to.equal(200); | ||
expect(res.body).to.deep.equal({ username: 'blakeembrey' }); | ||
expect(res.headers).to.deep.equal({ | ||
'content-type': 'application/json' | ||
}); | ||
}); | ||
return done(err); | ||
}); | ||
}); | ||
@@ -84,12 +83,11 @@ }); | ||
it('should make a request to get a new access token', function (done) { | ||
return currentToken.refresh(function (err, token) { | ||
expect(token).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(token.accessToken).to.equal('def456token'); | ||
expect(token.tokenType).to.equal('bearer'); | ||
return done(err); | ||
}); | ||
it('should make a request to get a new access token', function () { | ||
return currentToken.refresh() | ||
.then(function (token) { | ||
expect(token).to.an.instanceOf(ClientOAuth2.Token); | ||
expect(token.accessToken).to.equal('def456token'); | ||
expect(token.tokenType).to.equal('bearer'); | ||
}); | ||
}); | ||
}); | ||
}); |
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
23
150
0
52102
1
16
1316
+ Addedpopsicle@0.0.2
+ Addedajv@6.12.6(transitive)
+ Addedasn1@0.2.6(transitive)
+ Addedassert-plus@1.0.0(transitive)
+ Addedasync@0.9.2(transitive)
+ Addedasynckit@0.4.0(transitive)
+ Addedaws-sign2@0.7.0(transitive)
+ Addedaws4@1.13.0(transitive)
+ Addedbcrypt-pbkdf@1.0.2(transitive)
+ Addedcaseless@0.12.0(transitive)
+ Addedcombined-stream@0.0.71.0.8(transitive)
+ Addedcore-util-is@1.0.2(transitive)
+ Addeddashdash@1.14.1(transitive)
+ Addeddelayed-stream@0.0.51.0.0(transitive)
+ Addedecc-jsbn@0.1.2(transitive)
+ Addedextend@3.0.2(transitive)
+ Addedextsprintf@1.3.0(transitive)
+ Addedfast-deep-equal@3.1.3(transitive)
+ Addedfast-json-stable-stringify@2.1.0(transitive)
+ Addedforever-agent@0.6.1(transitive)
+ Addedform-data@0.1.42.3.3(transitive)
+ Addedgetpass@0.1.7(transitive)
+ Addedhar-schema@2.0.0(transitive)
+ Addedhar-validator@5.1.5(transitive)
+ Addedhttp-signature@1.2.0(transitive)
+ Addedis-typedarray@1.0.0(transitive)
+ Addedisstream@0.1.2(transitive)
+ Addedjsbn@0.1.1(transitive)
+ Addedjson-schema@0.4.0(transitive)
+ Addedjson-schema-traverse@0.4.1(transitive)
+ Addedjson-stringify-safe@5.0.1(transitive)
+ Addedjsprim@1.4.2(transitive)
+ Addedmime@1.2.11(transitive)
+ Addedmime-db@1.52.0(transitive)
+ Addedmime-types@2.1.35(transitive)
+ Addedoauth-sign@0.9.0(transitive)
+ Addedperformance-now@2.1.0(transitive)
+ Addedpopsicle@0.0.2(transitive)
+ Addedpsl@1.9.0(transitive)
+ Addedpunycode@2.3.1(transitive)
+ Addedqs@6.5.3(transitive)
+ Addedrequest@2.88.2(transitive)
+ Addedsafe-buffer@5.2.1(transitive)
+ Addedsafer-buffer@2.1.2(transitive)
+ Addedsshpk@1.18.0(transitive)
+ Addedtough-cookie@2.5.0(transitive)
+ Addedtunnel-agent@0.6.0(transitive)
+ Addedtweetnacl@0.14.5(transitive)
+ Addeduri-js@4.4.1(transitive)
+ Addeduuid@3.4.0(transitive)
+ Addedverror@1.10.0(transitive)