client-oauth2
Advanced tools
Comparing version 0.1.0 to 0.2.0
@@ -0,7 +1,9 @@ | ||
/* global define */ | ||
(function (root) { | ||
var isBrowser = typeof window === 'object'; | ||
var hasBuffer = typeof Buffer === 'function'; | ||
var _hasOwnProperty = Object.prototype.hasOwnProperty; | ||
var btoa = hasBuffer ? btoaBuffer : root.btoa; | ||
var popsicle = isBrowser ? root.popsicle : require('popsicle'); | ||
var hasRequire = typeof require === 'function' | ||
var hasBuffer = typeof Buffer === 'function' | ||
var _hasOwnProperty = Object.prototype.hasOwnProperty | ||
var btoa = hasBuffer ? btoaBuffer : root.btoa | ||
var popsicle = hasRequire ? require('popsicle') : root.popsicle | ||
@@ -63,3 +65,3 @@ /** | ||
].join(' ') | ||
}; | ||
} | ||
@@ -75,7 +77,7 @@ /** | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i]; | ||
var source = arguments[i] | ||
for (var key in source) { | ||
if (_hasOwnProperty.call(source, key)) { | ||
dest[key] = source[key]; | ||
dest[key] = source[key] | ||
} | ||
@@ -85,3 +87,3 @@ } | ||
return dest; | ||
return dest | ||
} | ||
@@ -96,3 +98,3 @@ | ||
function btoaBuffer (string) { | ||
return new Buffer(string).toString('base64'); | ||
return new Buffer(string).toString('base64') | ||
} | ||
@@ -110,7 +112,6 @@ | ||
for (var i = 0; i < props.length; i++) { | ||
var prop = props[i]; | ||
var prop = props[i] | ||
// Check whether the property is empty. | ||
if (obj[prop] == null) { | ||
throw new TypeError('Expected "' + prop + '" to exist'); | ||
throw new TypeError('Expected "' + prop + '" to exist') | ||
} | ||
@@ -128,3 +129,3 @@ } | ||
function omit (source, keys) { | ||
var obj = {}; | ||
var obj = {} | ||
@@ -134,7 +135,7 @@ // Iterate over the source object and set properties on a new object. | ||
if (keys.indexOf(key) === -1) { | ||
obj[key] = source[key]; | ||
obj[key] = source[key] | ||
} | ||
}); | ||
}) | ||
return obj; | ||
return obj | ||
} | ||
@@ -151,33 +152,33 @@ | ||
function decodeQuery (qs, sep, eq) { | ||
eq = eq || '='; | ||
sep = sep || '&'; | ||
qs = qs.split(sep); | ||
eq = eq || '=' | ||
sep = sep || '&' | ||
qs = qs.split(sep) | ||
var obj = {}; | ||
var maxKeys = 1000; | ||
var len = Math.min(qs.length, maxKeys); | ||
var obj = {} | ||
var maxKeys = 1000 | ||
var len = Math.min(qs.length, maxKeys) | ||
for (var i = 0; i < len; i++) { | ||
var key = qs[i].replace(/\+/g, '%20'); | ||
var value = ''; | ||
var index = key.indexOf(eq); | ||
var key = qs[i].replace(/\+/g, '%20') | ||
var value = '' | ||
var index = key.indexOf(eq) | ||
if (index !== -1) { | ||
value = key.substr(index + 1); | ||
key = key.substr(0, index); | ||
value = key.substr(index + 1) | ||
key = key.substr(0, index) | ||
} | ||
key = decodeURIComponent(key); | ||
value = decodeURIComponent(value); | ||
key = decodeURIComponent(key) | ||
value = decodeURIComponent(value) | ||
if (!_hasOwnProperty.call(obj, key)) { | ||
obj[key] = value; | ||
obj[key] = value | ||
} else if (Array.isArray(obj[key])) { | ||
obj[key].push(value); | ||
obj[key].push(value) | ||
} else { | ||
obj[key] = [obj[key], value]; | ||
obj[key] = [obj[key], value] | ||
} | ||
} | ||
return obj; | ||
return obj | ||
} | ||
@@ -194,6 +195,6 @@ | ||
data.error || | ||
data.error_message; | ||
data.error_message | ||
// Return an error instance with the message if it exists. | ||
return message && new Error(message); | ||
return message && new Error(message) | ||
} | ||
@@ -208,11 +209,11 @@ | ||
function handleAuthResponse (res) { | ||
var data = res.body; | ||
var err = getAuthError(data); | ||
var data = res.body | ||
var err = getAuthError(data) | ||
// If the response contains an error, reject the refresh token. | ||
if (err) { | ||
return Promise.reject(err); | ||
return Promise.reject(err) | ||
} | ||
return data; | ||
return data | ||
} | ||
@@ -228,6 +229,6 @@ | ||
if (!Array.isArray(scopes)) { | ||
return scopes == null ? '' : String(scopes); | ||
return scopes == null ? '' : String(scopes) | ||
} | ||
return scopes.join(' '); | ||
return scopes.join(' ') | ||
} | ||
@@ -243,3 +244,3 @@ | ||
function createUri (options, tokenType) { | ||
// Check the required parameters have been set. | ||
// Check the required parameters are set. | ||
expects(options, [ | ||
@@ -249,20 +250,41 @@ 'clientId', | ||
'authorizationUri' | ||
]); | ||
]) | ||
var clientId = encodeURIComponent(options.clientId); | ||
var redirectUri = encodeURIComponent(options.redirectUri); | ||
var scopes = encodeURIComponent(sanitizeScope(options.scopes)); | ||
var uri = options.authorizationUri + '?client_id=' + clientId + | ||
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; | ||
'&response_type=' + tokenType | ||
if (options.state) { | ||
uri += '&state=' + encodeURIComponent(options.state); | ||
uri += '&state=' + encodeURIComponent(options.state) | ||
} | ||
return uri; | ||
return uri | ||
} | ||
/** | ||
* Create basic auth header. | ||
* | ||
* @param {String} username | ||
* @param {String} password | ||
* @return {String} | ||
*/ | ||
function auth (username, password) { | ||
return 'Basic ' + btoa(string(username) + ':' + string(password)) | ||
} | ||
/** | ||
* Ensure a value is a string. | ||
* | ||
* @param {String} str | ||
* @return {String} | ||
*/ | ||
function string (str) { | ||
return str == null ? '' : String(str) | ||
} | ||
/** | ||
* Construct an object that can handle the multiple OAuth 2.0 flows. | ||
@@ -273,8 +295,9 @@ * | ||
function ClientOAuth2 (options) { | ||
this.options = options; | ||
this.options = options | ||
this.code = new CodeFlow(this); | ||
this.token = new TokenFlow(this); | ||
this.owner = new OwnerFlow(this); | ||
this.credentials = new CredentialsFlow(this); | ||
this.code = new CodeFlow(this) | ||
this.token = new TokenFlow(this) | ||
this.owner = new OwnerFlow(this) | ||
this.credentials = new CredentialsFlow(this) | ||
this.jwt = new JwtBearerFlow(this) | ||
} | ||
@@ -287,3 +310,3 @@ | ||
*/ | ||
ClientOAuth2.Token = ClientOAuth2Token; | ||
ClientOAuth2.Token = ClientOAuth2Token | ||
@@ -301,9 +324,9 @@ /** | ||
data = assign({}, data, { | ||
access_token: access, | ||
access_token: access, | ||
refresh_token: refresh, | ||
token_type: type | ||
}); | ||
token_type: type | ||
}) | ||
return new ClientOAuth2Token(this, data); | ||
}; | ||
return new ClientOAuth2Token(this, data) | ||
} | ||
@@ -321,10 +344,10 @@ /** | ||
if (res.status < 200 || res.status >= 300) { | ||
var err = new Error('HTTP status ' + res.status); | ||
err.status = res.status; | ||
return Promise.reject(err); | ||
var err = new Error('HTTP status ' + res.status) | ||
err.status = res.status | ||
return Promise.reject(err) | ||
} | ||
return res; | ||
}); | ||
}; | ||
return res | ||
}) | ||
} | ||
@@ -334,3 +357,3 @@ /** | ||
*/ | ||
ClientOAuth2.prototype.request = popsicle; | ||
ClientOAuth2.prototype.request = popsicle | ||
@@ -344,3 +367,3 @@ /** | ||
function ClientOAuth2Token (client, data) { | ||
this.client = client; | ||
this.client = client | ||
@@ -350,14 +373,26 @@ this.data = omit(data, [ | ||
'state', 'error', 'error_description', 'error_uri' | ||
]); | ||
]) | ||
this.tokenType = (data.token_type || 'bearer').toLowerCase(); | ||
this.accessToken = data.access_token; | ||
this.refreshToken = data.refresh_token; | ||
this.tokenType = (data.token_type || 'bearer').toLowerCase() | ||
this.accessToken = data.access_token | ||
this.refreshToken = data.refresh_token | ||
// Set the expiration date. | ||
if (data.expires_in) { | ||
this.expires = new Date(); | ||
this.expiresIn(data.expires_in) | ||
} | ||
this.expires.setSeconds(this.expires.getSeconds() + data.expires_in); | ||
/** | ||
* Expire after some seconds. | ||
* | ||
* @param {Number} duration | ||
* @return {Date} | ||
*/ | ||
ClientOAuth2Token.prototype.expiresIn = function (duration) { | ||
if (!isNaN(duration)) { | ||
this.expires = new Date() | ||
this.expires.setSeconds(this.expires.getSeconds() + duration) | ||
} else { | ||
this.expires = undefined | ||
} | ||
return this.expires | ||
} | ||
@@ -373,26 +408,26 @@ | ||
if (!this.accessToken) { | ||
throw new Error('Unable to sign without access token'); | ||
throw new Error('Unable to sign without access token') | ||
} | ||
opts.headers = opts.headers || {}; | ||
opts.headers = opts.headers || {} | ||
if (this.tokenType === 'bearer') { | ||
opts.headers.Authorization = 'Bearer ' + this.accessToken; | ||
opts.headers.Authorization = 'Bearer ' + this.accessToken | ||
} else { | ||
var parts = opts.uri.split('#'); | ||
var token = 'access_token=' + this.accessToken; | ||
var uri = parts[0].replace(/[?&]access_token=[^&#]/, ''); | ||
var fragment = parts[1] ? '#' + parts[1] : ''; | ||
var parts = opts.uri.split('#') | ||
var token = 'access_token=' + this.accessToken | ||
var uri = parts[0].replace(/[?&]access_token=[^&#]/, '') | ||
var fragment = parts[1] ? '#' + parts[1] : '' | ||
// Prepend the correct query string parameter to the uri. | ||
opts.uri = uri + (uri.indexOf('?') > -1 ? '&' : '?') + token + fragment; | ||
opts.uri = uri + (uri.indexOf('?') > -1 ? '&' : '?') + token + fragment | ||
// Attempt to avoid storing the uri in proxies, since the access token | ||
// is exposed in the query parameters. | ||
opts.headers.Pragma = 'no-store'; | ||
opts.headers['Cache-Control'] = 'no-store'; | ||
opts.headers.Pragma = 'no-store' | ||
opts.headers['Cache-Control'] = 'no-store' | ||
} | ||
return opts; | ||
}; | ||
return opts | ||
} | ||
@@ -406,4 +441,4 @@ /** | ||
ClientOAuth2Token.prototype.request = function (opts) { | ||
return this.client.request(this.sign(opts)); | ||
}; | ||
return this.client.request(this.sign(opts)) | ||
} | ||
@@ -416,11 +451,9 @@ /** | ||
ClientOAuth2Token.prototype.refresh = function () { | ||
var self = this; | ||
var options = this.client.options; | ||
var self = this | ||
var options = this.client.options | ||
if (!this.refreshToken) { | ||
return Promise.reject(new Error('No refresh token set')); | ||
return Promise.reject(new Error('No refresh token set')) | ||
} | ||
var authorization = btoa(options.clientId + ':' + options.clientSecret); | ||
return this.client._request({ | ||
@@ -430,9 +463,9 @@ url: options.accessTokenUri, | ||
headers: { | ||
'Accept': 'application/json, application/x-www-form-urlencoded', | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
'Authorization': 'Basic ' + authorization | ||
'Accept': 'application/json, application/x-www-form-urlencoded', | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
'Authorization': auth(options.clientId, options.clientSecret) | ||
}, | ||
body: { | ||
refresh_token: this.refreshToken, | ||
grant_type: 'refresh_token' | ||
grant_type: 'refresh_token' | ||
} | ||
@@ -442,10 +475,11 @@ }) | ||
.then(function (data) { | ||
// Update stored tokens on the current instance. | ||
self.accessToken = data.access_token; | ||
self.refreshToken = data.refresh_token; | ||
self.accessToken = data.access_token | ||
self.refreshToken = data.refresh_token | ||
return self; | ||
}); | ||
}; | ||
self.expiresIn(data.expires_in) | ||
return self | ||
}) | ||
} | ||
/** | ||
@@ -458,7 +492,7 @@ * Check whether the token has expired. | ||
if (this.expires) { | ||
return Date.now() < this.expires.getTime(); | ||
return Date.now() < this.expires.getTime() | ||
} | ||
return false; | ||
}; | ||
return false | ||
} | ||
@@ -473,3 +507,3 @@ /** | ||
function OwnerFlow (client) { | ||
this.client = client; | ||
this.client = client | ||
} | ||
@@ -485,5 +519,4 @@ | ||
OwnerFlow.prototype.getToken = function (username, password) { | ||
var self = this; | ||
var options = this.client.options; | ||
var authorization = btoa(options.clientId + ':' + options.clientSecret); | ||
var self = this | ||
var options = this.client.options | ||
@@ -494,10 +527,10 @@ return this.client._request({ | ||
headers: { | ||
'Accept': 'application/json, application/x-www-form-urlencoded', | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
'Authorization': 'Basic ' + authorization | ||
'Accept': 'application/json, application/x-www-form-urlencoded', | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
'Authorization': auth(options.clientId, options.clientSecret) | ||
}, | ||
body: { | ||
scope: sanitizeScope(options.scopes), | ||
username: username, | ||
password: password, | ||
scope: sanitizeScope(options.scopes), | ||
username: username, | ||
password: password, | ||
grant_type: 'password' | ||
@@ -508,5 +541,5 @@ } | ||
.then(function (data) { | ||
return new ClientOAuth2Token(self, data); | ||
}); | ||
}; | ||
return new ClientOAuth2Token(self.client, data) | ||
}) | ||
} | ||
@@ -521,3 +554,3 @@ /** | ||
function TokenFlow (client) { | ||
this.client = client; | ||
this.client = client | ||
} | ||
@@ -532,6 +565,6 @@ | ||
TokenFlow.prototype.getUri = function (options) { | ||
options = assign({}, this.client.options, options); | ||
options = assign({}, this.client.options, options) | ||
return createUri(options, 'token'); | ||
}; | ||
return createUri(options, 'token') | ||
} | ||
@@ -546,12 +579,12 @@ /** | ||
TokenFlow.prototype.getToken = function (uri, state) { | ||
var data = {}; | ||
var options = this.client.options; | ||
var data = {} | ||
var options = this.client.options | ||
// Make sure the uri matches our expected redirect uri. | ||
if (uri.substr(0, options.redirectUri.length) !== options.redirectUri) { | ||
return Promise.reject(new Error('Should match redirect uri: ' + uri)); | ||
return Promise.reject(new Error('Should match redirect uri: ' + uri)) | ||
} | ||
var queryIndex = uri.indexOf('?'); | ||
var fragmentIndex = uri.indexOf('#'); | ||
var queryIndex = uri.indexOf('?') | ||
var fragmentIndex = uri.indexOf('#') | ||
@@ -561,3 +594,3 @@ // If no query string or fragment exists, we won't be able to parse | ||
if (queryIndex === -1 && fragmentIndex === -1) { | ||
return Promise.reject(new Error('Unable to process uri: ' + uri)); | ||
return Promise.reject(new Error('Unable to process uri: ' + uri)) | ||
} | ||
@@ -568,6 +601,6 @@ | ||
if (queryIndex > -1 && queryIndex < fragmentIndex) { | ||
var endIndex = fragmentIndex === -1 ? uri.length : fragmentIndex; | ||
var query = uri.slice(queryIndex + 1, endIndex); | ||
var endIndex = fragmentIndex === -1 ? uri.length : fragmentIndex | ||
var query = uri.slice(queryIndex + 1, endIndex) | ||
assign(data, decodeQuery(query)); | ||
assign(data, decodeQuery(query)) | ||
} | ||
@@ -578,12 +611,12 @@ | ||
if (fragmentIndex > -1) { | ||
var fragment = uri.substr(fragmentIndex + 1); | ||
var fragment = uri.substr(fragmentIndex + 1) | ||
assign(data, decodeQuery(fragment)); | ||
assign(data, decodeQuery(fragment)) | ||
} | ||
var err = getAuthError(data); | ||
var err = getAuthError(data) | ||
// Check if the query string was populated with a known error. | ||
if (err) { | ||
return Promise.reject(err); | ||
return Promise.reject(err) | ||
} | ||
@@ -593,8 +626,8 @@ | ||
if (state != null && data.state !== state) { | ||
return Promise.reject(new Error('Invalid state: ' + data.state)); | ||
return Promise.reject(new Error('Invalid state: ' + data.state)) | ||
} | ||
// Initalize a new token and return. | ||
return Promise.resolve(new ClientOAuth2Token(this, data)); | ||
}; | ||
return Promise.resolve(new ClientOAuth2Token(this.client, data)) | ||
} | ||
@@ -609,3 +642,3 @@ /** | ||
function CredentialsFlow (client) { | ||
this.client = client; | ||
this.client = client | ||
} | ||
@@ -620,5 +653,5 @@ | ||
CredentialsFlow.prototype.getToken = function (options) { | ||
var self = this; | ||
var self = this | ||
options = assign({}, this.client.options, options); | ||
options = assign({}, this.client.options, options) | ||
@@ -629,7 +662,4 @@ expects(options, [ | ||
'accessTokenUri' | ||
]); | ||
]) | ||
// Base64 encode the client id and secret for the Authorization header. | ||
var authorization = btoa(options.clientId + ':' + options.clientSecret); | ||
return this.client._request({ | ||
@@ -639,8 +669,8 @@ url: options.accessTokenUri, | ||
headers: { | ||
'Accept': 'application/json, application/x-www-form-urlencoded', | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
'Authorization': 'Basic ' + authorization | ||
'Accept': 'application/json, application/x-www-form-urlencoded', | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
'Authorization': auth(options.clientId, options.clientSecret) | ||
}, | ||
body: { | ||
scope: sanitizeScope(options.scopes), | ||
scope: sanitizeScope(options.scopes), | ||
grant_type: 'client_credentials' | ||
@@ -651,5 +681,5 @@ } | ||
.then(function (data) { | ||
return new ClientOAuth2Token(self, data); | ||
}); | ||
}; | ||
return new ClientOAuth2Token(self.client, data) | ||
}) | ||
} | ||
@@ -664,3 +694,3 @@ /** | ||
function CodeFlow (client) { | ||
this.client = client; | ||
this.client = client | ||
} | ||
@@ -674,6 +704,6 @@ | ||
CodeFlow.prototype.getUri = function (options) { | ||
options = assign({}, this.client.options, options); | ||
options = assign({}, this.client.options, options) | ||
return createUri(options, 'code'); | ||
}; | ||
return createUri(options, 'code') | ||
} | ||
@@ -689,4 +719,4 @@ /** | ||
CodeFlow.prototype.getToken = function (uri, state) { | ||
var self = this; | ||
var options = this.client.options; | ||
var self = this | ||
var options = this.client.options | ||
@@ -698,26 +728,26 @@ expects(options, [ | ||
'accessTokenUri' | ||
]); | ||
]) | ||
// Make sure the uri matches our expected redirect uri. | ||
if (uri.substr(0, options.redirectUri.length) !== options.redirectUri) { | ||
return Promise.reject(new Error('Should match redirect uri: ' + uri)); | ||
return Promise.reject(new Error('Should match redirect uri: ' + uri)) | ||
} | ||
var queryIndex = uri.indexOf('?'); | ||
var fragmentIndex = uri.indexOf('#'); | ||
var queryIndex = uri.indexOf('?') | ||
var fragmentIndex = uri.indexOf('#') | ||
if (queryIndex === -1) { | ||
return Promise.reject(new Error('Unable to process uri: ' + uri)); | ||
return Promise.reject(new Error('Unable to process uri: ' + uri)) | ||
} | ||
var endIndex = fragmentIndex === -1 ? uri.length : fragmentIndex; | ||
var data = decodeQuery(uri.slice(queryIndex + 1, endIndex)); | ||
var err = getAuthError(data); | ||
var endIndex = fragmentIndex === -1 ? uri.length : fragmentIndex | ||
var data = decodeQuery(uri.slice(queryIndex + 1, endIndex)) | ||
var err = getAuthError(data) | ||
if (err) { | ||
return Promise.reject(err); | ||
return Promise.reject(err) | ||
} | ||
if (state && data.state !== state) { | ||
return Promise.reject(new Error('Invalid state:' + data.state)); | ||
return Promise.reject(new Error('Invalid state:' + data.state)) | ||
} | ||
@@ -727,3 +757,3 @@ | ||
if (!data.code) { | ||
return Promise.reject(new Error('Missing code, unable to request token')); | ||
return Promise.reject(new Error('Missing code, unable to request token')) | ||
} | ||
@@ -735,10 +765,10 @@ | ||
headers: { | ||
'Accept': 'application/json, application/x-www-form-urlencoded', | ||
'Accept': 'application/json, application/x-www-form-urlencoded', | ||
'Content-Type': 'application/x-www-form-urlencoded' | ||
}, | ||
body: { | ||
code: data.code, | ||
grant_type: 'authorization_code', | ||
redirect_uri: options.redirectUri, | ||
client_id: options.clientId, | ||
code: data.code, | ||
grant_type: 'authorization_code', | ||
redirect_uri: options.redirectUri, | ||
client_id: options.clientId, | ||
client_secret: options.clientSecret | ||
@@ -749,18 +779,68 @@ } | ||
.then(function (data) { | ||
return new ClientOAuth2Token(self, data); | ||
}); | ||
}; | ||
return new ClientOAuth2Token(self.client, data) | ||
}) | ||
} | ||
/** | ||
* Export the OAuth2 client for multiple environments. | ||
* Support JSON Web Token (JWT) Bearer Token OAuth 2.0 grant. | ||
* | ||
* Reference: https://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-12#section-2.1 | ||
* | ||
* @param {ClientOAuth2} client | ||
*/ | ||
function JwtBearerFlow (client) { | ||
this.client = client | ||
} | ||
/** | ||
* Request an access token using a JWT token. | ||
* | ||
* @param {string} token A JWT token. | ||
* @param {Object} [options] | ||
* @return {Promise} | ||
*/ | ||
JwtBearerFlow.prototype.getToken = function (token, options) { | ||
var self = this | ||
options = assign({}, this.client.options, options) | ||
expects(options, [ | ||
'accessTokenUri' | ||
]) | ||
var headers = { | ||
'Accept': 'application/json, application/x-www-form-urlencoded', | ||
'Content-Type': 'application/x-www-form-urlencoded' | ||
} | ||
// Authentication of the client is optional, as described in Section 3.2.1 of OAuth 2.0 [RFC6749] | ||
if (options.clientId) { | ||
headers['Authorization'] = auth(options.clientId, options.clientSecret) | ||
} | ||
return this.client._request({ | ||
url: options.accessTokenUri, | ||
method: 'POST', | ||
headers: headers, | ||
body: { | ||
scope: sanitizeScope(options.scopes), | ||
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', | ||
assertion: token | ||
} | ||
}) | ||
.then(handleAuthResponse) | ||
.then(function (data) { | ||
return new ClientOAuth2Token(self.client, data) | ||
}) | ||
} | ||
if (typeof define === 'function' && define.amd) { | ||
define([], function () { | ||
return ClientOAuth2; | ||
}); | ||
return ClientOAuth2 | ||
}) | ||
} else if (typeof exports === 'object') { | ||
module.exports = ClientOAuth2; | ||
module.exports = ClientOAuth2 | ||
} else { | ||
root.ClientOAuth2 = ClientOAuth2; | ||
root.ClientOAuth2 = ClientOAuth2 | ||
} | ||
})(this); | ||
})(this) |
{ | ||
"name": "client-oauth2", | ||
"version": "0.1.0", | ||
"version": "0.2.0", | ||
"description": "Straight-forward library for executing OAuth 2.0 flows and making API requests.", | ||
"main": "client-oauth2.js", | ||
"files": [ | ||
"client-oauth2.js", | ||
"LICENSE" | ||
], | ||
"scripts": { | ||
"test": "gulp lint && gulp test" | ||
"lint": "standard", | ||
"test-browser": "karma start", | ||
"test-node": "mocha -R spec --bail --require test/support/globals.js", | ||
"test": "npm run lint && npm run test-node && npm run test-browser" | ||
}, | ||
@@ -25,10 +32,8 @@ "repository": { | ||
"devDependencies": { | ||
"chai": "^1.9.1", | ||
"chai": "^2.0.0", | ||
"es6-promise": "^2.0.0", | ||
"gulp": "^3.8.6", | ||
"gulp-jshint": "^1.8.4", | ||
"gulp-mocha": "^2.0.0", | ||
"is-travis": "^1.0.0", | ||
"karma": "^0.12.23", | ||
"karma-chrome-launcher": "^0.1.4", | ||
"karma-cli": "0.0.4", | ||
"karma-coverage": "^0.2.6", | ||
@@ -38,10 +43,9 @@ "karma-firefox-launcher": "^0.1.3", | ||
"karma-phantomjs-launcher": "^0.1.4", | ||
"karma-sinon-chai": "^0.2.0", | ||
"karma-sinon-chai": "^0.3.0", | ||
"mocha": "^2.0.1", | ||
"nock": "^0.51.0", | ||
"require-dir": "^0.1.0" | ||
"standard": "^2.6.2" | ||
}, | ||
"dependencies": { | ||
"popsicle": "0.0.2" | ||
"popsicle": "^0.3.10" | ||
} | ||
} |
@@ -142,2 +142,13 @@ # Client OAuth 2.0 | ||
### [JWT as Authorization Grant](https://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-12#section-2.1) | ||
> A JSON Web Token (JWT) Bearer Token can be used to request an access token when a client wishes to utilize an existing trust relationship, expressed through the semantics of (and digital signature or Message Authentication Code calculated over) the JWT, without a direct user approval step at the authorization server. | ||
```javascript | ||
githubAuth.jwt.getToken('eyJhbGciOiJFUzI1NiJ9.eyJpc3Mi[...omitted for brevity...].J9l-ZhwP[...omitted for brevity...]') | ||
.then(function (user) { | ||
console.log(user); //=> { accessToken: '...', tokenType: 'bearer', ... } | ||
}); | ||
``` | ||
## License | ||
@@ -144,0 +155,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
13
161
29512
4
694
1
+ Addedform-data@0.2.0(transitive)
+ Addedmime-db@1.12.0(transitive)
+ Addedmime-types@2.0.14(transitive)
+ Addedpopsicle@0.3.11(transitive)
- Removedform-data@0.1.4(transitive)
- Removedmime@1.2.11(transitive)
- Removedpopsicle@0.0.2(transitive)
Updatedpopsicle@^0.3.10