Frontend Development 15 min read

Token Silent Refresh in Frontend Development: Concepts, Strategies, and Implementation

This article explains the fundamentals of token‑based authentication, the drawbacks of fixed token lifetimes, and presents multiple silent‑refresh techniques—including double‑token mechanisms, front‑end timers, server‑side proactive refresh, and concurrency‑safe lock strategies—along with practical code examples and performance considerations for high‑concurrency scenarios.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Token Silent Refresh in Frontend Development: Concepts, Strategies, and Implementation

1. Introduction

In front‑end development, user authentication is often implemented with tokens, but their limited lifespan forces users to re‑login when they expire, harming user experience. "Token silent refresh" is a common optimization that automatically renews tokens without user interaction.

2. Token Basics and Pain Points

2.1 How Tokens Work

Tokens (e.g., JWT or OAuth2 access tokens) are issued by the server after a successful login and are sent with each request in headers or parameters. The server validates the token to confirm the user's identity and permissions.

2.2 Problems with Fixed Expiration

Problem Category

Specific Issue

Example Scenario

Poor User Experience

Frequent re‑login due to short lifetimes (e.g., 15 minutes)

User filling a long form loses data when the token expires.

Security Risks

Long‑lived tokens (e.g., 7 days) can be stolen and abused

Attacker accesses user data for a week after token theft.

High‑Concurrency Performance

Mass token expiry at the same time overloads the server

All users' tokens expire on the hour, causing a spike in refresh requests.

Dynamic Adaptation

Static lifetimes cannot adjust to user behavior or risk level

Payments need short tokens, browsing can use longer ones.

3. What Is Token Silent Refresh?

When an access token expires, the system automatically obtains a new token so the user does not notice any interruption. The goals are to improve user experience, maintain security, and optimise performance.

Application Scenarios

Single‑page web apps (Vue, React, Angular) where users may stay idle for long periods.

Mobile apps that run in the background for extended times.

Multi‑device synchronization where one device’s token expiry should not affect others.

Real‑time communication apps that require continuous server connections.

4. Technical Implementations

4.1 Double‑Token Mechanism (Access Token + Refresh Token)

The server issues a short‑lived access token and a long‑lived refresh token. When the access token expires, the client uses the refresh token to obtain a new access token.

import axios from 'axios'
const service = axios.create({
  baseURL: 'https://api.example.com',
  timeout: 10000
})

// Request interceptor – add Access Token
service.interceptors.request.use(config => {
  const accessToken = localStorage.getItem('access_token');
  if (accessToken) {
    config.headers.Authorization = `Bearer ${accessToken}`;
  }
  return config;
});

// Response interceptor – handle 401 and refresh token
service.interceptors.response.use(
  response => response,
  async error => {
    const originalRequest = error.config;
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      try {
        const accessToken = await refreshToken();
        localStorage.setItem('access_token', accessToken);
        originalRequest.headers.Authorization = `Bearer ${accessToken}`;
        return service(originalRequest);
      } catch (refreshError) {
        router.push('/login');
      }
    }
    return Promise.reject(error);
  }
);

async function refreshToken() {
  try {
    const response = await service.get('/refresh', {
      params: { token: getRefreshTokenFromCookie() },
      timeout: 30000
    });
    return response.data.accessToken;
  } catch (error) {
    localStorage.removeItem('access_token');
    localStorage.removeItem('refresh_token');
    throw error;
  }
}

export default service;

4.2 Front‑End Timed Refresh

The client proactively refreshes the token before it expires, typically one minute in advance.

let refreshTimeout;
function checkAndRefreshToken() {
  const accessToken = localStorage.getItem('accessToken');
  if (accessToken) {
    const expiresIn = getTokenExpiresIn(accessToken);
    if (expiresIn < 60) {
      refreshAccessToken().then(newAccessToken => {
        localStorage.setItem('accessToken', newAccessToken);
        refreshTimeout = setTimeout(checkAndRefreshToken, (getTokenExpiresIn(newAccessToken) - 60) * 1000);
      });
    } else {
      refreshTimeout = setTimeout(checkAndRefreshToken, (expiresIn - 60) * 1000);
    }
  }
}
checkAndRefreshToken();

4.3 Server‑Side Proactive Refresh

The server checks the remaining lifetime on each request and, if it is below a threshold, returns a new access token in the response headers.

// Server middleware
app.use((req, res, next) => {
  const accessToken = req.headers.authorization?.split(' ')[1];
  if (accessToken) {
    const expiresIn = getTokenExpiresIn(accessToken);
    if (expiresIn < 60) {
      const newAccessToken = generateAccessToken(req.user);
      res.set('New-Access-Token', newAccessToken);
    }
  }
  next();
});

// Client response interceptor
service.interceptors.response.use(response => {
  const newAccessToken = response.headers['new-access-token'];
  if (newAccessToken) {
    localStorage.setItem('accessToken', newAccessToken);
  }
  return response;
});

4.4 Double Token + Concurrency Lock

In high‑concurrency environments, a lock and request queue prevent multiple simultaneous refreshes.

// Request interceptor – add token
service.interceptors.request.use(config => {
  if (config.url !== '/login') {
    const accessToken = localStorage.getItem('access_token');
    config.headers['Authorization'] = `Bearer ${accessToken}`;
  }
  if (config.url === '/refresh_token') {
    const refreshToken = localStorage.getItem('refresh_token');
    config.headers['Authorization'] = `Bearer ${refreshToken}`;
  }
  return config;
});

let isRefreshing = false;
let failedQueue = [];
const processQueue = (error, token = null) => {
  failedQueue.forEach(prom => {
    if (error) prom.reject(error);
    else prom.resolve(token);
  });
  if (!error) failedQueue = [];
};

service.interceptors.response.use(
  response => response,
  async error => {
    const originalRequest = error.config;
    if (error.response.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      if (!isRefreshing) {
        isRefreshing = true;
        try {
          const accessToken = await refreshToken();
          localStorage.setItem('access_token', accessToken);
          originalRequest.headers['Authorization'] = `Bearer ${accessToken}`;
          processQueue(null, accessToken);
          return service(originalRequest);
        } catch (err) {
          processQueue(err, null);
          router.push('/login');
        } finally {
          isRefreshing = false;
        }
      } else {
        return new Promise((resolve, reject) => {
          failedQueue.push({ resolve, reject });
        });
      }
    }
    return Promise.reject(error);
  }
);

export default service;

5. Summary

Token silent refresh improves user experience and security. Various methods—double‑token, front‑end timer, server‑side proactive refresh, and lock‑based concurrency handling—suit different scenarios, each with its own advantages and trade‑offs.

Method

Applicable Scenarios

Advantages

Disadvantages

Double Token Mechanism

General purpose

High security, low refresh frequency

Requires server support for two tokens

Front‑End Timed Refresh

Highly active users

Avoids sudden expiry during requests

Needs timer management

Double Token + Concurrency Lock

High‑concurrency environments

Solves concurrent refresh problems

Complex implementation

Server‑Side Proactive Refresh

Server‑controlled scenarios

No extra client logic needed

Increases server load

frontendAuthenticationAxiosJWTtokensilent refresh
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.