I have an existing single page application that I have transitioned to JWT instead of PHP sessions. Its working well but I am trying to figure out how to refresh the JWT (if necessary) BEFORE AJAX requests.
A little background: Upon user login I store a JWT (10 minute expiration) and a Refresh Token (2 hour expiration). I have the following function that I want to run prior to EVERY AJAX call to the API. The function checks if the JWT is expired and if so it retrieves a new one via the Refresh token. Obviously in the API I check the validity of both the JWT and Refresh token before allowing data to be sent back. This part is working perfectly.
function checkTokenExp(){
var validToken = false; // DEFAULT TO EXPIRED
var apiClaims = localStorage.getItem('apiToken').split('.');
var api = JSON.parse(atob(apiClaims[1]));
var apiExpiration = new Date(api['exp'] * 1000);
var now = new Date();
if (apiExpiration < now) {
// API TOKEN EXPIRED - CHECK REFRESH TOKEN
var refreshClaims = localStorage.getItem('refreshToken').split('.');
var refresh = JSON.parse(atob(refreshClaims[1]));
var refreshExpiration = new Date(refresh['exp'] * 1000);
if (refreshExpiration > now) {
// REFRESH TOKEN NOT EXPIRED - NEED NEW API TOKEN
$.ajax({
type: "GET",
url: 'api/session/token',
contentType: 'application/json',
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", 'Bearer '+localStorage.getItem('refreshToken'));
}
}).done(function (data) {
var data = jQuery.parseJSON(data);
if (data.status == 'success'){
localStorage.setItem('apiToken', data.apiToken);
}
validToken = true;
});
}else{
// REFRESH TOKEN EXPIRED - FORCE LOG OUT
$("#SessionExpiredModal").modal('show');
}
}else{
// API TOKEN NOT EXPIRED
validToken = true;
}
return validToken;
}
Where I run into trouble is with the code below (and every other AJAX call going forward). As you can see, I am trying to run the function above before this AJAX call and validate my JWT (if its invalid a new one is requested and stored) and then run the AJAX call with the new JWT. It all works except the AJAX returns a 401 unauthorized because it is still sending the previous JWT (which is obviously expired). So it seems as though the AJAX is being sent before the above function completes and stores the new JWT. But I know my function is running correctly and the JWT is updated because the second time I click the button it runs correctly and I get the proper reply from the API.
$('#BtnTest').on('click', function(){
$.ajax({
type: "GET",
url: 'api/random',
contentType: 'application/json',
beforeSend: function (xhr) {
checkTokenExp(); // SHOULD BE SAVING NEW TOKEN
xhr.setRequestHeader("Authorization", 'Bearer '+ localStorage.getItem('apiToken')); // SHOULD BE SENDING NEW TOKEN
}
}).done(function (response) {
alert(response);
})
});
I hope that makes sense and thanks in advance for the help. Also, is there an easy way to make my function run before EVERY ajax call without having to code it in each AJAX statement.