Async token requests in $.ajax calls
Making Auth0’s new SPA SDK and Kendo UI’s DataSource play nice together
This past Labor Day weekend, I’d been working on integrating some Kendo UI Grids into BurnRate. As I tweeted at the time, I had forgotten how quickly Kendo lets you get productive with complex interfaces. I was up and running in very short order.
The majority of our front-end architecture uses the async Fetch API to make calls back to our API… so when we migrated to Auth0’s new SPA SDK recently, it was a fantastic fit.
Unfortunately for me though, Kendo UI is still making it’s network calls via $.ajax, and even though the $.ajax() call itself is Promise-aware, the beforeSend() method is not async/await ready. There are tricks you can use to make an async call inside it, but the beforeSend() method will return before the async call inside completes. So you can’t use those tricks for something like… retrieving a new JWT and adding it to an Authorization header.
Fortunately for you, I spend a half-day figuring out a solution, so you don’t have to.
var beforeSend = (req: JQueryXHR, settings: JQueryAjaxSettings) => {
// RWM: The first request won't have the headers, so break out of a beforeSend infinite loop.
if (settings.headers != null && settings.headers.Authorization != undefined) return true;// RWM: Abort the current request, get the token, and when that is finished re-submit the original request.
// Inspired by https://stackoverflow.com/a/32647118/403765
req.abort();
auth0.getTokenSilently().then(value => {
settings.headers = $.extend(settings.headers, { "Authorization": `Bearer ${value}` });
$.ajax(settings);
});
};
$.ajax() calls can be aborted without the beforeSend() method returning immediately. So we cancel the current request, trigger an async request to get the token, then take advantage of the Promise design to attach a new action after the token call completes. We then merge the Authorization header into any existing headers, and make the request again. Since the new request will trigger a new beforeSend() call, we quickly break out of that if we already have the Authorization header set from the previous request.
Since this method is reusable, you an assign it to all of your Kendo DataSource Transport definitions (except for Batch, which should be fixed in the Kendo UI Q4 release). You can also use it in non-Kendo situations as well.
Hope that helps! Stay safe out there, and keep coding!