Access Token & Refresh Token

Access Token problem

Like the above flow, we do not save the access token on the server, but on the client. This is called stateless, meaning the server does not store any state of any user.

Its disadvantage is that we cannot revoke the access token. You can see some examples below.

Example 1: On the server, we want to proactively log out a user but cannot, because there is no way to delete the access token on the client device.

Example 2: The client is hacked, resulting in the access token being exposed. The hacker gets the access token and can access protected resources. Even though the server knows that, it cannot refuse the hacked access token, because we only verify whether the access token is correct or not, but there is no mechanism to check whether the access token is on the blacklist or not.

For the second example, we can set the access token validity period to be short, for example 5 minutes, so if the access token is leaked, hackers will have less time to penetrate our resources. => reduce risks.

But this method is not very good, because it will cause the user to log out and have to login every 5 minutes, which is very unpleasant in terms of user experience.

At this time, people have come up with a way to minimize the above problems, which is to use Refresh Token.


What is Refresh Token?

Refresh Token is another token chain, created at the same time as Access Token. Refresh Token has a longer validity period than Access Token, for example 1 week, 1 month, 1 year...

The authentication flow with access token and refresh token will be updated as follows:

  1. The client sends a request to a protected resource on the server. If the client is not authenticated, the server returns a 401 Authorization error. The client sends their username and password to the server.

  2. The server verifies the provided authentication information against the user database. If the authentication information matches, the server generates 2 different JWTs , Access Token and Refresh Token, containing the payload user_id(or some field identifying the user). Access Token has a short duration (about 5 minutes). Refresh Token has a longer period (about 1 year). Refresh Token will be saved to the database, while Access Token will not.

  3. The server returns the access token and refresh token to the client.

  4. Client stores access token and refresh token in device memory (cookie, local storage,...).

  5. For subsequent requests, the client includes the access token in the request header.

  6. Server verifies access token with secret key to check if access token is valid.

  7. If valid, the server grants access to the requested resource.

  8. When the access token expires, the client sends a refresh token to the server to get a new access token.

  9. The server checks whether the refresh token is valid or exists in the database. If ok, the server will delete the old refresh token and create a new refresh token with the same expiration date (for example, the old one expires on October 5, 2023, the new one will also expire on October 5, 2023) and save it to the database. data, create new access tokens.

  10. The server returns a new access token and a new refresh token to the client.

  11. Client stores access token and new refresh token in device memory (cookie, local storage,...).

  12. The client can make subsequent requests with the new access token (the token refresh process takes place in the background so the client will not be logged out).

  13. When the user wants to log out, call the logout API, the server will delete the refresh token in the database, and at the same time the client must delete the access token and refresh token in the device memory.

  14. When the refresh token expires (or is invalid), the server will refuse the client's request. The client will now delete the access token and refresh token in the device memory and enter the logged out state.

The problem of inadequacy between theory and reality

The desire of authenticating with JWT is stateless, but above you notice that we save the refresh token in the database, this causes the server to store the user's state, meaning it is no longer stateless.

If we want more security, we cannot rigidly stay stateless, so combining stateless and stateful together seems more reasonable. Access Token is stateless, while Refresh Token is stateful.

This is the reason why I say there is a contradiction between theory and actual application, it is difficult to completely apply stateless to JWT in practice.

And there is another reason why I save refresh tokens in the database: refresh tokens last for a very long time. If I know who has lost refresh tokens, I can delete that user's refresh tokens in the database. This will make the system more secure.

Similarly, if I want to logout a certain user, I can also delete that person's refresh token in the database. After their access token expires, their attempt to refresh the token will not be successful and they will be logged out. The thing is that it's not instantaneous, you have to wait until the access token expires to log out.

We can also improve further by shortening the access token expiration time and using websocket to notify the client to logout immediately.


Answer ten thousand questions about JWT

Why create a new refresh token when we perform a token refresh?

Because if the refresh token is exposed, hackers can use it to get a new access token, which is quite dangerous. So even though the refresh token lasts a long time, every few minutes when the access token expires and the token refresh is performed, I create a new refresh token and delete the old refresh token.

Note that the new Refresh Token still retains the expiration date and time of the old Refresh Token . The old one expires on October 5, 2023, the new one will also expire on October 5, 2023.

This is called refresh token rotation .

How to revoke (revoke) an access token?

You can understand revoke here to mean revoke or disable

As I said above, the access token we designed is stateless, so there is no way to properly revoke immediately , we have to fight the fire through websocket and revoke refresh token.

If you want to revoke immediately, you must save the access token in the database. When you want to revoke, you can delete it in the database, but this will make the access token no longer stateless.

Are there ever two JWTs that overlap?

Have! If the payload and secret key are the same, the two JWTs will be the same.

Notice that in the JWT payload there will be a field iat(issued at) that is the time the JWT was created (this is the default field, unless you disable it). And iatit is measured in seconds.

So if we create 2 JWTs in the same second , then the fields iatof these 2 JWTs will be the same, plus the payload you transmit is the same, it will produce 2 identical JWTs.

Where should the access token and refresh token be saved on the client?

If you have a browser, you can save it in cookies or local storage, each has its own advantages and disadvantages. But cookies will have a "slight" advantage in terms of security.

For detailed comparison between local storage and cookies, I will have an article later.

If it is a mobile app, you can save it in the device's memory.

How to send access token to the server?

There will be 2 cases

  • Save cookie : It will automatically send every time a request comes to the server, no need to pay attention to it.

  • Save local storage : You add the header with the key Authorizationand value of Bearer <access_token>.

Why must Bearer be added before the access token?

Actually, whether you add it or not depends on how the backend server codes.

In order for the api authentication code to be standard, the server should require the client to add Bearerthe access token before it. The purpose of saying authentication is "Bearer Authentication" (token-based authentication).

Bearer Authentication is named after the word "bearer" which means "bearer" - i.e. whoever has this token will be considered the person with access to the requested resource. This is different from other authentication methods such as "Basic Authentication" or "Digest Authentication", which need to use user credentials.

Adding "Bearer" in front of the access token has several main purposes:

  1. Determine the authentication type : Provides information to the server about the authentication method the client wants to use. This helps the server process requests more accurately.

  2. Normality : Using the "Bearer" prefix helps ensure that applications and servers follow standard rules in how tokens are used and handled.

  3. Easy to differentiate : Adding "Bearer" helps differentiate between different types of tokens and authentication. For example, if the server supports multiple authentication methods, the word "Bearer" will help the server determine the type of authentication being used based on the token.

When using Bearer Authentication, the headers Authorizationin the HTTP request will look like this:

Authorization: Bearer your_access_token

When I log out, can I just delete the access token and refresh the token in the client's memory?

If you do not call the logout api but simply delete the access token and refresh the token in the client's memory, you will still be able to logout, but it will not be good for the system in terms of security. Because the refresh token still exists in the database, if hackers can get your refresh token, they can still get a new access token.

Last updated