box-chrome-sdk
Version:
A Chrome App SDK for the Box V2 API
121 lines (117 loc) • 5.76 kB
JavaScript
/**
* @fileoverview An angular module and service providing OAuth2 access to the SDK.
* @author jmeadows
*/
var auth = angular.module('box.auth', ['rx', 'box.conf', 'chrome.identity', 'crypto']);
auth.provider('boxApiAuth', [
'authUrl', 'clientId', 'clientSecret', 'redirectUri',
function(authUrl, clientId, clientSecret, redirectUri) {
var webAuthParams = {
url: authUrl + '/authorize?client_id=' + clientId + '&response_type=code&redirect_uri=' + redirectUri,
interactive: true
};
var throwError;
throwError = function() {
throw new Error('unknown error extracting code');
};
function parseWebAuthResponseWithState(state) {
return function parseWebAuthResponse(responseUrl) {
if (responseUrl) {
var error = responseUrl.match(/[&\?]error=([^&]+)/);
if (error) {
throw new Error('Error extracting code');
}
var csrfState = responseUrl.match(/[&\?]state=([\w\/\-]+)/);
if (! csrfState || csrfState[1] !== state) {
throw new Error('Returned csrf token does not match the one sent!');
}
return responseUrl.match(/[&\?]code=([\w\/\-]+)/)[1];
} else {
return throwError();
}
};
}
this.setThrowError = function(throwErrorFunc) {
throwError = throwErrorFunc;
};
var refreshObservable = null;
this.$get = ['rx', 'chromeIdentity', 'http', 'crypto', function(rx, chromeIdentity, http, crypto) {
return {
/**
* Present the user with a login form from Box, requesting their login and that they grant access to
* your application.
* @returns {Observable} An observable that will contain an authorization code if the user performs
* the login to Box successfully and grants access to your application.
*/
login: function() {
var randomArray = new Uint8Array(16);
crypto.getRandomValues(randomArray);
var state = 'box_csrf_token_' + Array.prototype.map.call(randomArray, function(i) {
var alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
return alphabet.charAt(i % alphabet.length);
}).join('');
var params = JSON.parse(JSON.stringify(webAuthParams));
params.url += '&state=' + state;
return chromeIdentity.login(params).map(parseWebAuthResponseWithState(state));
},
/**
* Exchange an authorization code for an authorization token.
* @param {String} code An authorization code returned from @see login
* @returns {Observable} An observable that will contain the HTTP result from the request
* to url https://www.box.com/api/oauth2 containing an authorization token and a refresh token.
*/
getToken: function(code) {
return http.request(
'POST',
authUrl + '/token',
null,
{
/*eslint-disable camelcase*/
grant_type: 'authorization_code',
code: code,
client_id: clientId,
client_secret: clientSecret,
redirect_uri: redirectUri
/*eslint-enable camelcase*/
}
);
},
/**
* Exchange a refresh token for a new authorization token.
* @param {String} refreshToken A refresh token returned from @see getToken or this function.
* @returns {Observable} An observable that will contain the HTTP result from the request
* to url https://www.box.com/api/oauth2 containing an authorization token and a refresh token.
*/
refreshToken: function(refreshToken) {
var subject = new rx.Subject();
if (refreshObservable === null) {
refreshObservable = http.request(
'POST',
authUrl + '/token',
null,
{
/*eslint-disable camelcase*/
grant_type: 'refresh_token',
refresh_token: refreshToken,
client_id: clientId,
client_secret: clientSecret,
redirect_uri: redirectUri
/*eslint-enable camelcase*/
}
)
.publish()
.refCount();
refreshObservable.subscribe(
angular.noop,
angular.noop,
function() {
refreshObservable = null;
}
);
}
refreshObservable.subscribe(subject);
return subject.asObservable();
}
};
}];
}]);