90 lines
3.8 KiB
JavaScript
90 lines
3.8 KiB
JavaScript
define([
|
|
'jquery',
|
|
'underscore',
|
|
'js/programs/utils/api_config'
|
|
],
|
|
function( $, _, apiConfig ) {
|
|
'use strict';
|
|
|
|
var auth = {
|
|
autoSync: {
|
|
/**
|
|
* Override Backbone.sync to seamlessly attempt (re-)authentication when necessary.
|
|
*
|
|
* If a 401 error response is encountered while making a request to the Programs,
|
|
* API, this wrapper will attempt to request an id token from a custom endpoint
|
|
* via AJAX. Then the original request will be retried once more.
|
|
*
|
|
* Any other response than 401 on the original API request, or any error occurring
|
|
* on the retried API request (including 401), will be handled by the base sync
|
|
* implementation.
|
|
*
|
|
*/
|
|
sync: function( method, model, options ) {
|
|
|
|
var oldError = options.error;
|
|
|
|
this._setHeaders( options );
|
|
|
|
options.notifyOnError = false; // suppress Studio error pop-up that will happen if we get a 401
|
|
|
|
options.error = function(xhr, textStatus, errorThrown) {
|
|
if (xhr && xhr.status === 401) {
|
|
// attempt auth and retry
|
|
this._updateToken(function() {
|
|
// restore the original error handler
|
|
options.error = oldError;
|
|
options.notifyOnError = true; // if it fails again, let Studio notify.
|
|
delete options.xhr; // remove the failed (401) xhr from the last try.
|
|
|
|
// update authorization header
|
|
this._setHeaders( options );
|
|
|
|
Backbone.sync.call(this, method, model, options);
|
|
}.bind(this));
|
|
} else if (oldError) {
|
|
// fall back to the original error handler
|
|
oldError.call(this, xhr, textStatus, errorThrown);
|
|
}
|
|
}.bind(this);
|
|
return Backbone.sync.call(this, method, model, options);
|
|
},
|
|
|
|
/**
|
|
* Fix up headers on an imminent AJAX sync, ensuring that the JWT token is enclosed
|
|
* and that credentials are included when the request is being made cross-domain.
|
|
*/
|
|
_setHeaders: function( ajaxOptions ) {
|
|
ajaxOptions.headers = _.extend ( ajaxOptions.headers || {}, {
|
|
Authorization: 'JWT ' + apiConfig.get( 'idToken' )
|
|
});
|
|
ajaxOptions.xhrFields = _.extend( ajaxOptions.xhrFields || {}, {
|
|
withCredentials: true
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Fetch a new id token from the configured endpoint, update the api config,
|
|
* and invoke the specified callback.
|
|
*/
|
|
_updateToken: function( success ) {
|
|
|
|
$.ajax({
|
|
url: apiConfig.get('authUrl'),
|
|
xhrFields: {
|
|
// See: https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
|
|
withCredentials: true
|
|
},
|
|
crossDomain: true
|
|
}).done(function ( data ) {
|
|
// save the newly-retrieved id token
|
|
apiConfig.set( 'idToken', data.id_token );
|
|
}).done( success );
|
|
}
|
|
}
|
|
};
|
|
|
|
return auth;
|
|
}
|
|
);
|