Reputation: 1168
Currently I am using JWT-Auth on my Laravel back-end to protect my API routes with a token. However, after a certain time the token gets invalid and I get the error 401 Unauthorized
. So I guess I have to refresh the token somewhere. When would be the best time to do this? I read about doing it every time you make a request but I want to be sure that’s the right way to do so. I used this guide from their docs: https://jwt-auth.readthedocs.io/en/develop/quick-start/#create-the-authcontroller. In here they make a function to fresh a token. But how would I implement this every time I make a request? Do I just call this function in the controller with an Axios
request or call it in another controller or something? Any tips are greatly appreciated.
I have a Vue.js front-end by the way.
Upvotes: 0
Views: 661
Reputation: 20737
With Tymon/JWTAuth you have two options:
jwt.refresh
middleware to your api routes, which will refresh the token everytime a request is made. The downside of this solution is that this could be abused. The upside is that you do not really need to worry about the token in your application, especially if you do not have a frontend or do not develop the frontend yourself.const token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEsImlzcyI6Imh0dHBzOi8vZXhhbXBsZS5jb20iLCJpYXQiOjE1NTUzNDkxMjYsImV4cCI6MTU1NTM3NzkyNiwibmJmIjoxNTU1MzQ5MTI2LCJqdGkiOiJtZEdTNGE2ZDJnNHM5NzRnNSJ9.TygbG5smlhAapE8fy4rgXlLVYW-qOcWtLYnnbgJCIKg";
function shouldRefreshToken(token) {
const currentTime = 1555350309829; // Date.now()
const universalTimestamp = currentTime / 1000;
const gracePeriod = 60 * 60 * 8; // 8 hours
const tokenParts = token.split('.');
const payload = JSON.parse(atob(tokenParts[1]));
if (payload.iat > universalTimestamp) {
console.log("This monstrosity was issued in the future O_o");
}
if (payload.nbf > universalTimestamp) {
console.log("This token is not valid yet. Refreshing it does not yield anything useful. Maybe we still have some previous token?");
}
if (payload.exp < universalTimestamp) {
console.log("This token has expired. We should try to refresh it before doing anything else.");
} else if (payload.exp - gracePeriod < universalTimestamp) {
console.log("This token is about to expire. We can refresh it asynchronously.");
} else {
console.log("Nah, we are fine!");
}
}
shouldRefreshToken(token);
In the end you would want to send a request to a refresh endpoint that does something like this, which is then parsed by the frontend:
$myNewToken = JWTAuth::refresh(JWTAuth::getToken());
response()->header('Authorization', "Bearer {$myNewToken}");
To get it to work, you can do something like this:
import store from '../store';
import { shouldRefreshToken } from '../helpers/auth';
const someBaseUrl = 'https://example.com';
export function request(options = {}) {
// Hopefully you rewrite that function above to return a boolean ;-)
if (shouldRefreshToken(store.state.auth.token)) {
refreshToken();
}
const config = {
method: options.method,
url: `${someBaseUrl}/${options.resource}`,
credentials: 'include',
headers: {
...(options.headers || {}),
Authorization: `Bearer ${store.state.auth.token}`,
'Content-Type': 'application/json'
},
data: options.data
}
return axios(config).then(parseResponse)
}
function parseResponse(axiosResponse) {
// Probably want to get the token and do something with it
}
function refreshToken() {
axios({
method: 'POST',
url: `${someBaseUrl}/refresh`
}).then(parseResponse)
}
Upvotes: 1