Maintaining API authentication using Axios


This is a story about how we, at AmpLive, are maintaining users authenticated 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?

  1. Ask for data and send your Authentication Token
  2. API is verifying your payload, token and is querying the database
  3. Database responds with data to API
  4. 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:

  1. Ask for data and send the Auth token
  2. Verify token expiration time
  3. If the token is expired use axios interceptor to prevent the request from being made
  4. Save the original request and send another one to your token refresh endpoint in order to get a new valid JWT Token
  5. Resolve the initial request
  6. Get the data you asked for
  7. 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!

A single golf clap? Or a long standing ovation?

By clapping more or less, you can signal to us which stories really stand out.