Introduction
I recently published a package on npm that allows developers to easily manage refresh tokens in their applications: axios-refresh-me. This package is designed to be simple, secure, and efficient. It simplifies the process of managing token expiration and retrying failed requests, ensuring a smoother user experience.
In this article, I will explain why i created this package and how you can use it to manage refresh tokens in your applications.
But before we dive into the details, let's take a look at what refresh tokens are and why they are important.
Refresh tokens
A refresh token is a special token that is used to obtain more access tokens. This allows you to have short-lived access tokens without having to collect credentials every time one expires. You request a refresh token alongside the access and/or ID tokens as part of a user's initial authentication and authorization flow. Apps must then securely store refresh tokens since they allow users to remain authenticated.
Purpose of a Refresh Token
Why do we need refresh tokens?
The main reason why refresh tokens exist is because most access tokens don't live forever. That is to say, an access token may expire after a specific period of time like a few hours or days. Hence, in order to avoid requesting that the client perform an activity like entering a username and password to retrieve a new access token, you can use refresh tokens to get a new access token.
On the side of user experience, imagine forcing your users to log in every time they return to your application after the access token expires . Most popular services seamlessly allow users to return to their previous session by silently generating new access tokens using refresh tokens.
In a situation where a malicious user gets a hold of a valid access token, they can make requests on behalf of a user and access protected data. As a result, access tokens expire after some time and become invalid. Refresh tokens, on the other hand, live longer so that your application can make use of it to retrieve a new access token. In order to increase the security of your application, you should avoid exposing refresh tokens.
A secure way to send refresh tokens back to a client application is through HTTP-only cookies.
How Refresh Tokens Work Under the Hood
- Initial Authentication
- User login: The user submits credentials (e.g., username/password).
- Server Response: The server validates credentials and returns:
- Short-lived Access Token: Typically in the response body (e.g., JWT valid for 15 minutes).
- Long-lived Refresh Token: Sent as an HTTP-only, Secure, SameSite cookie to mitigate XSS/CSRF risks. The client cannot directly read this token.
- Storing Tokens Securely
-
Access Token: Stored in-memory (e.g., React state, context) or a transient storage like sessionStorage (cleared on tab close).
-
Refresh Token: Automatically managed by the browser via HTTP-only cookies. Never exposed to client-side JavaScript.
- Handling Access Token Expiration
When an API returns 401 Unauthorized, the access token is likely expired.
Axios Interceptor catches the error and triggers a token refresh. We also need a flag and a queue to prevent multiple requests from refreshing the token simultaneously.
This setup ensures that the user remains authenticated and can continue using the application without interruption.
Axios-refresh-me
So you may ask, what is the purpose of the axios-refresh-me
package?
Take a look at the following example (You can also turn on devtools to see waterfall at the network tab):
Try setting token to invalid and see how the above example handles the refresh token.
Why there are two refresh token requests? If you notice the first request is a failed request with a 401 status code and trigger the refresh token flow, but the second request took a lot more time to complete.
And by the time the second request is completed, it triggers the refresh token flow again due to the invalid token and the cycle continues.
Another issue is that if the refresh token request is not fufilled yet, there is a change that more requests will be made during this time and all of them will be failed thus triggering the refresh token flow multiple times. (Try Fetch data while the refresh token request is pending)
This is where the axios-refresh-me
package comes in . It makes sure that only one refresh token request is made at a time and all the failed requests are queued and resolved once the token is refreshed.
How it works
So how does the axios-refresh-me
package work?
When the first request fails with a 401 status code, the package will trigger the refresh token flow and cancel all the pending requests, the failed and canceled requests are queued and resolved once the token is refreshed.
This can be done by using the AbortController API which allows you to cancel pending requests.
With this API, we can address the first issue where multiple refresh token requests are made.
But how do we handle the second issue where more requests are made while the refresh token request is pending?
This can be a bit tricky, instead of queuing the failed requests and resolving them in axios response interceptor, we can
move the logic to the request interceptor and make sure that the request is made only after the token is refreshed.
By moving the logic to the request interceptor, we can make the incoming requests wait until the token is refreshed and then proceed with the queued requests.
Here is how the axios-refresh-me
package handles the refresh token flow:
Here's the source code of axios-refresh-me
package, if you curious about how it implemented:
https://github.com/D4r1inG/axios-refresh-me/tree/main
Conclusion
Refresh tokens are a powerful tool to keep users logged in for a long time. They can improve the user experience and the general security of an application. However, managing refresh tokens can be challenging, especially when dealing with multiple requests and token expiration.
The axios-refresh-me
package simplifies the process of managing refresh tokens by ensuring that only one refresh token request is made at a time and all the failed requests are queued and resolved once the token is refreshed.
I hope this article has helped you understand the importance of refresh tokens and how you can use them securely and efficiently in your applications.
So how about using the axios-refresh-me
package in your next project?
Happy coding!