Handling Access Token Expiration Gracefully

Strategies for handling expired access tokens including proactive refresh, retry with refresh, and silent re-authentication patterns.

Token Management

Detailed Explanation

Handling Token Expiration

Access tokens are intentionally short-lived (typically 5-60 minutes). When they expire, API requests return 401 Unauthorized. A well-designed client handles this transparently without disrupting the user experience.

Strategy 1: Proactive Refresh

Check the token's expiration before each API request. If it expires within a buffer window (e.g., 30 seconds), refresh proactively:

async function apiRequest(url, options = {}) {
  // Check if token expires soon (30-second buffer)
  if (tokenExpiresAt - Date.now() < 30000) {
    await refreshAccessToken();
  }

  return fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      Authorization: `Bearer ${accessToken}`,
    },
  });
}

Strategy 2: Reactive Refresh (401 Retry)

Attempt the request. If it returns 401, refresh the token and retry once:

async function apiRequest(url, options = {}) {
  let response = await fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      Authorization: `Bearer ${accessToken}`,
    },
  });

  if (response.status === 401) {
    await refreshAccessToken();
    response = await fetch(url, {
      ...options,
      headers: {
        ...options.headers,
        Authorization: `Bearer ${accessToken}`,
      },
    });
  }

  return response;
}

Strategy 3: Token Refresh Queue

When multiple API requests fail simultaneously, avoid making multiple refresh requests. Use a queue:

let refreshPromise = null;

async function ensureValidToken() {
  if (refreshPromise) return refreshPromise;
  refreshPromise = refreshAccessToken().finally(() => {
    refreshPromise = null;
  });
  return refreshPromise;
}

When Refresh Fails

If the refresh token is also expired or revoked:

  1. Clear all stored tokens
  2. Redirect the user to the login page
  3. Preserve the user's current URL for post-login redirect
  4. Show a user-friendly message ("Your session has expired. Please sign in again.")

Best Practices

  • Always check expires_in from the token response to calculate expiration time
  • Use a buffer (30-60 seconds) to avoid edge cases
  • Implement a single-flight refresh mechanism to prevent concurrent refresh requests
  • Handle network errors during refresh gracefully

Use Case

A React application that makes frequent API calls. The app uses an Axios interceptor to check for 401 responses, automatically refreshes the access token using the stored refresh token, and retries the original request — all transparent to the user.

Try It — OAuth 2.0 Flow Visualizer

Open full tool