Maintaining API authentication using Axios
Some time passed since my last story and I felt like it’s time to tell you more about what intrigued me a lot these days. After digging in on axios github issue page and Google, I found out that there’s no proper documented way of maintaining an user authenticated if you’re using React and axios.
How a request is served?
- Ask for data and send your Authentication Token
- API is verifying your payload, token and is querying the database
- Database responds with data to API
- API is sending data back
Simple, right? :) So, what happens if your Authentication Token has expired. You can’t ask the user to login again. It’s bad user experience. That’s why refresh tokens have been invented.
A refresh token allows the user to ask the API to issue a new token directly, without needing to re-authenticate.
So, let’s say your token just expired and you want to request some data from the API. JWT is composed from three layers: a header, a payload, and a signature. The payload have some reserved fields like issuer, expiration, subject and audience. So you can always check the expiration time if you don’t encode the token (remember: JWT tokens should be short-lived ~ 15 min — 1hour)
The diagram above will transform into the following:
- Ask for data and send the Auth token
- Verify token expiration time
- If the token is expired use axios interceptor to prevent the request from being made
- Save the original request and send another one to your token refresh endpoint in order to get a new valid JWT Token
- Resolve the initial request
- Get the data you asked for
- Be happy :)
Coding time, right?
client.interceptors.request.use((config) => {
let originalRequest = config;
if (tokenIsExpired && path_is_not_login) {
return issueToken().then((token) => {
originalRequest['Authorization'] = 'Bearer ' + token;
return Promise.resolve(originalRequest);
});
}
return config;
}, (err) => {
return Promise.reject(err);
});
For the sake of the example, let’s see the implementation for issueToken:
function issueToken() {
return new Promise((resolve, reject) => {
return client({
...
}).then((response) => {
resolve(response);
}).catch((err) => {
reject(err);
});
});
}
Easy, right? ;)
Hope this helps you. It took me a while to research how to better use interceptors and to figure out when to send the re-auth request.
Happy coding!