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

Summary of 10 must-see JavaScript interview questions (recommended)

1.This points to 1. Who calls whom? example: func...

(MariaDB) Comprehensive explanation of MySQL data types and storage mechanisms

1.1 Data Type Overview The data type is a field c...

Vue achieves the top effect through v-show

html <div class="totop" v-show="...

Detailed explanation of the installation process of Jenkins on CentOS 7

Install Jenkins via Yum 1. Installation # yum sou...

jQuery plugin to implement minesweeper game (1)

This article shares the specific code of the firs...

JS ES new features template string

Table of contents 1. What is a template string? 2...

How to change the CentOS server time to Beijing time

1. I purchased a VPS and CentOS system, and found...

Example usage of Linux compression file command zip

The ".zip" format is used to compress f...

Website Building Tutorial for Beginners: Learn to Build a Website in Ten Days

The 10-day tutorial uses the most understandable ...

MySQL 5.7.15 version installation and configuration method graphic tutorial

This article shares with you a detailed tutorial ...

SQL group by to remove duplicates and sort by other fields

need: Merge identical items of one field and sort...

Steps for packaging and configuring SVG components in Vue projects

I just joined a new company recently. After getti...

JavaScript implements mouse drag to adjust div size

This article shares the specific code of JavaScri...