JWT Multiple Request Refresh Token
You have an SPA application on the React / Vue / Angular / etc framework, authorization through JWT and many routes for receiving different information from the server. To all this, you have a closed application, that is, authorization is required to access any page.
When the user has not visited the site for a long time, the validity period of his token has expired, but he can still get a new one based on the old token. So, the user goes directly to some internal page where you need to send several requests to get the current user, some widgets, a list, and more.
You probably already have some logic on request, by type:
- 3 requests are sent: get the current user, get widget number 1 data, get some list on the page.
- The server returns a response with an error with status code 401 to the first request. You most likely process it globally (axios interceptors), send another request to the server to try to get a new token, then repeat the request.
- But before they manage to get a new token, as 2 other requests are also sent with old tokens, and they repeat the same logic.
- The first one successfully updated the token, saved it somewhere, and the other two fall, because the old token is already in the blacklist and you cannot get a new one through it.
Let’s write a primitive server on nodejs and connect 2 libraries: jsonwebtoken via package and axios via CDN.
$ npm init
$ npm i -S jsonwebtoken
Now we will write a small code for basic authorization, token recovery and receiving some data. Also, for writing less logic — only the GET method will be supported, all in one file, some moments in the implementation will be missed.
We will have several routes:
- / — for getting HTML page
- /api/login — user authorization by login and password (in fact, only by login)
- /api/refresh — attempt to get a new token based on the current
- /api/secret — to receive secret data, authorization is required
- /api/public — receive public data, authorization is not needed
Now let’s create a small HTML page where we try to execute a few queries
to receive secret and public data. This code is written in ES6, without Babel, I hope your browser supports it :)
Now let’s take a look at our requests in various situations:
- Case #1. We are a guest, without any token.
- Case #2. We are an authorized user with a valid token.
- Case #3. We are an authorized user with a token expired, with the ability to get a new one.
- Case #4. We are an authorized user with a token expired without the ability to get a new one.
The site itself looks like this.
You can try it yourself, link to the Github repository.