Axios Unsensory Refresh Token is a technology that automatically refreshes access tokens in front-end applications, ensuring that users do not interrupt operations due to the token expiration when making API requests.
- Access Token: The credentials used to access protected resources usually have a certain validity period.
- Refresh Token: Used to obtain a new access token, which is used when the access token expires.
Implementation steps:
- Setting the interceptor: Add logic to Axios' request interceptor to check the current time and the expiration time of the token. If the access token has expired but the refresh token is still valid, the refresh token interface is called to obtain the new access token.
- Update token storage: Once a new access token is obtained, store it in localStorage, Vuex, or other state management tools for subsequent requests to use the new token.
- Retry the original request: After the token is successfully refreshed, the intercepted request is resent, and the new access token is used.
XMLHttpRequest
// Create an XMLHttpRequest instanceconst xhr = new XMLHttpRequest(); // Save Token and Refresh Token after logging in successfullyfunction onLoginSuccess(response) { ('accessToken', ); ('refreshToken', ); } // Function to initiate the requestfunction sendRequest(url, method, data) { return new Promise((resolve, reject) => { (method, url); ('Authorization', `Bearer ${('accessToken')}`); = function() { if ( === 4) { if ( === 200) { resolve(()); } else { reject({ status: , response: }); } } }; if (method === 'POST' && data) { ((data)); } else { (); } }); } // Function to refresh the tokenasync function refreshToken() { const refreshToken = ('refreshToken'); const response = await fetch('/path/to/refresh', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: ({ refresh_token: refreshToken }), }); const res = await (); if () { ('accessToken', ); return true; // means refresh is successful } else { return false; // Indicates that the refresh failed } } // Intercept the response and handle the Token refresh('readystatechange', function() { if ( === 4 && === 401) { refreshToken().then(refreshed => { if (refreshed) { ('Authorization', `Bearer ${('accessToken')}`); (); // Resend the request } else { alert('Please log in again'); // Token refresh failed, the user may need to log in again } }); } });
Axios
import axios from 'axios'; // Create an Axios instanceconst apiClient = ({ baseURL: '', // Other configurations...}); // Response Interceptor(response => { return response; }, error => { const { response } = error; if (response && === 401) { return refreshToken().then(refreshed => { if (refreshed) { // The token refreshes successfully, retry the original request return (); } else { // The token refresh failed and the user may need to log in again return (error); } }); } return (error); }); // Token refresh functionfunction refreshToken() { return ('/path/to/refresh', { // Parameters required to refresh the token, such as refresh_token }).then(response => { if () { // Assume that the response data contains a new access token const newAccessToken = ; // Update token storage ('accessToken', newAccessToken); // Update the headers of the Axios instance so that subsequent requests use new tokens ['Authorization'] = `Bearer ${newAccessToken}`; return true; // means refresh is successful } else { return false; // Indicates that the refresh failed } }); }
Fetch API
// Define a function to handle Fetch requestsasync function fetchWithToken(url, options = {}) { const token = ('token'); if (token) { = { ..., 'Authorization': `Bearer ${token}` }; } try { const response = await fetch(url, options); if ( === 401) { // Suppose 401 means that the token expires const refreshToken = ('refreshToken'); if (!refreshToken) { throw new Error('No refresh token available'); } // Call the refresh token interface const refreshResponse = await fetch('/api/refresh-token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: ({ refreshToken }) }); if () { const data = await (); ('token', ); // Retry the original request ['Authorization'] = `Bearer ${}`; return fetch(url, options); } else { throw new Error('Failed to refresh token'); } } return response; } catch (error) { ('Fetch error:', error); throw error; } } // Use examplefetchWithToken('/api/protected-resource') .then(response => ()) .then(data => (data)) .catch(error => ('Error:', error));
- fetchWithToken function:This is a function that encapsulates the Fetch API, which first checks whether the access token exists in the local storage and adds the token in the request header. If the response status code is 401 (indicating that the token expires), try to get the new access token using the refresh token and resend the original request.
- Refresh token logic:When the token expires, the function calls the refresh token interface and stores the new access token in the local storage. It then resets the authorization information in the request header and resends the original request.
- Error handling:If an error occurs during refreshing the token or sending the request, the function will throw the corresponding error and record the error message in the console.
JQ
// Create a JQuery instanceconst apiClient = $.ajaxSetup({ baseURL: '', // Other configurations...}); // Response Interceptor$.ajaxSetup({ complete: function(jqXHR, textStatus) { if (textStatus === 'error' && === 401) { return refreshToken().then(refreshed => { if (refreshed) { // The token refreshes successfully, retry the original request return (this); } else { // The token refresh failed and the user may need to log in again alert('Please log in again'); } }); } } }); // Token refresh functionfunction refreshToken() { return $.ajax({ url: '/path/to/refresh', method: 'POST', data: { refresh_token: ('refreshToken') }, dataType: 'json' }).then(response => { if () { // Assume that the response data contains a new access token const newAccessToken = ; // Update token storage ('accessToken', newAccessToken); // Update the headers of the JQuery instance so that subsequent requests use new tokens ['Authorization'] = `Bearer ${newAccessToken}`; return true; // means refresh is successful } else { return false; // Indicates that the refresh failed } }); }
// Import the encapsulated request pluginimport http from './interface'; import { getRefreshToken } from '@/common/api/'; // Refresh the token interface let isRefreshing = false; // Is it in refresh token statelet fetchApis = []; // Container that sends requests at the same time after failurelet refreshCount = 0; // Limit the maximum number of refresh without feeling function onFetch(newToken) { refreshCount += 1; if (refreshCount === 3) { refreshCount = 0; fetchApis = []; return (); } (callback => { callback(newToken); }); // Clear the cache interface fetchApis = []; return (); } // Response Interceptor((response) => { if () { (); } // Error handling when the request is successful but the interface returns if ( && + !== 200) { if (!) { ('error', response); ({ title: 'hint', content: , showCancel: false, confirmText: 'knew' }); // Interrupt return new Promise(() => {}); } else { // reject Promise return (); } } return response; }, (error) => { const token = ('token'); const refreshToken = ('refreshToken'); // DESC: No need to do a whitelist interface without feeling refresh const whiteFetchApi = ['/dealersystem/jwtLogin', '/dealersystem/smsLogin', '/sso2/login', '/dealersystem/isLogin']; switch () { case 401: case 402: if (token && !()) { if (!isRefreshing) { isRefreshing = true; getRefreshToken({ refreshToken }).then(res => { let newToken = ; onTokenFetched(newToken).then(res => {}).catch(err => { // When the number of loops exceeds the number, return to the login page, where you can add the logic for logging out. ({ title: 'Login is invalid, please log in again', icon: 'error' }); setTimeout(() => { ({ url: '/pages/login/login' }); }, 1500); }); }).catch(err => { // An error has been reported by the refreshToken interface, which proves that the refreshToken has expired. There is no way to log in again. ({ title: 'Login is invalid, please log in again', icon: 'error' }); setTimeout(() => { ({ url: '/pages/login/login' }); }, 1500); }).finally(() => { isRefreshing = false }); } return new Promise((resolve) => { // The promise here is very important, which is to ensure that your interface returns value resolves here for subsequent code execution addFetchApi((newToken) => { ['Authorization'] = `Bearer ${newToken}`; ().then(response => { resolve(response); }); }); }); } break; default: break; } });
Notes:
- Error handling: Ensure that when the refresh token fails, there is an appropriate error handling mechanism, such as prompting the user to log in again.
- Concurrent requests: To handle multiple requests, you need to refresh the token at the same time, and avoid repeated refreshes.
- Security: Ensure the secure storage and transmission of refresh tokens to prevent them from being acquired by malicious attackers.
Summarize
This is the end of this article about front-end sensing-free refresh tokens. For more related front-end sensing-free refresh token content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!