How to achieve seamless token refresh

How to achieve seamless token refresh

Preface:

Recently, when I was working on a demand, it involved a login token , and the product raised a question: Can token expiration time be longer? I need to log in frequently.

Frontend: Backend, can you set the token expiration time to be longer?

Backend: Yes, but it is not safe to do so, you can use a better method.

Front-end: What method?

Backend: Provides an interface for refreshing tokens and refreshes tokens regularly

Front-end: OK, let me think about it.

1. Demand

When token expires, refresh token . The front end needs to refresh token without any sense, that is, the user should not be aware of it when refreshing token to avoid frequent logins. Implementation ideas

Method 1

The backend returns the expiration time, the frontend determines token expiration time, and calls the refresh to interface

Disadvantages: The backend needs to provide an additional field for token expiration time; the local time is used for judgment. If the local time is tampered with, especially when the local time is slower than the server time, the interception will fail.

Method 2

Write a timer to refresh the token interface regularly

Disadvantages: waste of resources, consumption of performance, not recommended.

Method 3

Intercept in the response interceptor, determine that token is returned expired, and call the refresh token interface

2. Implementation

The basic framework of axios , using service.interceptors.response for interception

import axios from 'axios'

service.interceptors.response.use(
  response => {
    if (response.data.code === 409) {
        return refreshToken({ refreshToken: localStorage.getItem('refreshToken'), token: getToken() }).then(res => {
          const { token } = res.data
          setToken(token)
          response.headers.Authorization = `${token}`
        }).catch(err => {
          removeToken()
          router.push('/login')
          return Promise.reject(err)
        })
    }
    return response && response.data
  },
  (error) => {
    Message.error(error.response.data.msg)
    return Promise.reject(error)
  })

3. Problem Solving

Question 1: How to prevent multiple token refreshes

We use a variable isRefreshing to control whether token status is being refreshed.

import axios from 'axios'

service.interceptors.response.use(
  response => {
    if (response.data.code === 409) {
      if (!isRefreshing) {
        isRefreshing = true
        return refreshToken({ refreshToken: localStorage.getItem('refreshToken'), token: getToken() }).then(res => {
          const { token } = res.data
          setToken(token)
          response.headers.Authorization = `${token}`
        }).catch(err => {
          removeToken()
          router.push('/login')
          return Promise.reject(err)
        }).finally(() => {
          isRefreshing = false
        })
      }
    }
    return response && response.data
  },
  (error) => {
    Message.error(error.response.data.msg)
    return Promise.reject(error)
  })

Question 2: When two or more requests are initiated at the same time, how do other interfaces solve this problem?

When the second expired request comes in, token is being refreshed. We first store this request in an array queue and try to keep this request waiting until token is refreshed, then retry one by one to clear the request queue. So how do we keep this request waiting? To solve this problem, we have to use Promise . After storing the request in the queue, a Promise is returned at the same time, so that the Promise is always in Pending state (that is, resolve is not called). At this time, the request will keep waiting. As long as we do not execute resolve , the request will keep waiting. When the refresh request interface is returned, we call resolve again and try again one by one.

Final code:

import axios from 'axios'

//Whether it is refreshing let isRefreshing = false
//Retry queue let requests = []
service.interceptors.response.use(
  response => {
  //Agreed code 409 token expired if (response.data.code === 409) {
      if (!isRefreshing) {
        isRefreshing = true
        //Call refresh token interface return refreshToken({ refreshToken: localStorage.getItem('refreshToken'), token: getToken() }).then(res => {
          const { token } = res.data
          // Replace token
          setToken(token)
          response.headers.Authorization = `${token}`
           // After token is refreshed, re-execute the array method requests.forEach((cb) => cb(token))
          requests = [] // Re-request and clear return service(response.config)
        }).catch(err => {
        //Jump to the login page removeToken()
          router.push('/login')
          return Promise.reject(err)
        }).finally(() => {
          isRefreshing = false
        })
      } else {
        // Returns a Promise that has not been resolved
        return new Promise(resolve => {
          // Save resolve in function form and wait for refresh before executing requests.push(token => {
            response.headers.Authorization = `${token}`
            resolve(service(response.config))
          })
        })
      }
    }
    return response && response.data
  },
  (error) => {
    Message.error(error.response.data.msg)
    return Promise.reject(error)
  }
)

This is the end of this article on how to implement seamless token refresh. For more information on implementing seamless token refresh, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • SpringBoot JWT implements token login refresh function
  • About Vue to eliminate repeated prompts when refreshing the page when the Token expires
  • Detailed explanation of uniapp painless token refresh method
  • Detailed explanation of JWT refresh token in ASP.NET Core Web Api
  • Automatically refresh token operation when token expires during request
  • Implementation of SpringSecurity Jwt Token automatic refresh
  • Refresh token process analysis based on springboot+jwt
  • Example code of axios interceptor token refresh mechanism under vue
  • Laravel (Lumen) solves the problem of JWT-Auth refreshing token

<<:  Build a Docker image using Dockerfile

>>:  Color hexadecimal color code table display and hexadecimal value comparison display for easy search

Recommend

Installation steps of Ubuntu 20.04 double pinyin input method

1. Set up Chinese input method 2. Set the double ...

Implementation of MySQL scheduled database backup (full database backup)

Table of contents 1. MySQL data backup 1.1, mysql...

Detailed explanation of fuser command usage in Linux

describe: fuser can show which program is current...

Docker image compression and optimization operations

The reason why Docker is so popular nowadays is m...

How to install Graphviz and get started tutorial under Windows

Download and installConfigure environment variabl...

How to implement remote automatic backup of MongoDB in Linux

Preface After reading the previous article about ...

Do designers need to learn to code?

Often, after a web design is completed, the desig...

Typical cases of MySQL index failure

Table of contents Typical Cases Appendix: Common ...

Analysis of MySQL concurrency issues and solutions

Table of contents 1. Background 2. Slow query cau...

An article to show you how to create and use Vue components

Table of contents 1. What is a component? 2. Crea...

How to install Postgres 12 + pgadmin in local Docker (support Apple M1)

Table of contents introduce Support Intel CPU Sup...

Web front-end development experience summary

XML files should be encoded in utf-8 as much as p...

A brief discussion on the Linux kernel's support for floating-point operations

Currently, most CPUs support floating-point units...