Files
edx-platform/cms/static/js/programs/utils/auth_utils.js

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;
}
);