I have a jquery based functionality that prefilters all ajax queries so it can intercept 401 requests and refresh api authorization. I used to use a function that simply checks for a 401, refreshes the auth and reissues the initial query. The problem there was that many refreshes would get triggered at once, usually leading to a failure. I replaced it with something that checks whether a refresh is happening and if yes adds queries to a queue. Now the issue I am having is that the original queries are failing the promise and erroring out before being re-run and succeeding. This is an issue for some functions that don't work after the subsequent re-run. I want the ajax reissue to be transparent so I don't have to error-handle every single ajax call. The simpler code didn't have this issue. Unfortunately I don't have enough knowledge to figure out the promise logic.

The prefilter code is as follows

var refreshQueue = []; function addQueue(cb) { refreshQueue.push(cb); } function onRefreshed(token) { refreshQueue.forEach(cb => cb(token)); refreshQueue = []; } $.ajaxPrefilter(function(options, originalOptions, jqXHR) { // Skip refresh endpoint itself if (options.url.includes('/refresh') || options.url.includes('refresh')) { return; } // Add token to every request var token = localStorage.getItem('access_token'); if (token) { jqXHR.setRequestHeader('Authorization', 'Bearer ' + token); } // Hook into the fail handler jqXHR.fail(function(jqXHR, textStatus, errorThrown) { if (jqXHR.status === 401 && !originalOptions._retry) { var retryOriginalRequest = new $.Deferred(); if (isRefreshing) { // Wait for the ongoing refresh addQueue(function(newToken) { // Retry with new token originalOptions.headers = originalOptions.headers || {}; console.log(originalOptions); // originalOptions.headers['Authorization'] = 'Bearer ' + newToken; originalOptions._retry = true; $.ajax(originalOptions) .then(retryOriginalRequest.resolve, retryOriginalRequest.reject); }); } else { // Start refresh isRefreshing = true; $.ajax({ url: 'api/refresh', method: 'POST', contentType: 'application/json', data: JSON.stringify({ access_token: localStorage.getItem('access_token') // or refresh_token: localStorage.getItem('refresh_token') }) }) .done(function(res) { var newToken = res.access_token || res.token; localStorage.setItem('access_token', newToken); // Update global headers for future requests $.ajaxSetup({ headers: { 'Authorization': 'Bearer ' + newToken } }); onRefreshed(newToken); // Retry original // originalOptions.headers['Authorization'] = 'Bearer ' + newToken; originalOptions._retry = true; $.ajax(originalOptions).then(retryOriginalRequest.resolve, retryOriginalRequest.reject); }) .fail(function() { console.log("Refresh fail"); onRefreshed(null); // notify all waiting requests failed // Optional: logout // localStorage.clear(); // location.href = '/login'; retryOriginalRequest.reject(jqXHR, textStatus, errorThrown); }) .always(function() { isRefreshing = false; }); } jqXHR.then(null, function() { return retryOriginalRequest; }); } }); });```

Kryten's user avatar

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.