Real World Example

Handling 401 and 403 Differently in the App

Good apps react differently to the two codes. When your Gmail or Amazon session expires, you are sent to the login page and then back to where you were (401). When a Flipkart support agent opens a finance-only screen, they see "You don't have access, ask your manager" and stay logged in (403). Treating 403 like 401 (logging the user out) is a common and annoying bug.

// src/api.js (response interceptor, final version)
api.interceptors.response.use(
  (response) => response,
  async (error) => {
    const { response, config } = error;
    if (!response) return Promise.reject(error);          // network error

    if (response.status === 401 && !config._retry && !config.url.startsWith('/auth/')) {
      config._retry = true;
      try {
        await refreshAccessToken();                         // silent refresh
        return api(config);
      } catch {
        window.location.assign('/login?expired=1&next=' + encodeURIComponent(window.location.pathname));
      }
    }

    if (response.status === 403) {
      // stay logged in, just tell the user
      window.dispatchEvent(new CustomEvent('shopease:forbidden', { detail: response.data.message }));
    }
    return Promise.reject(error);
  },
);

// src/components/ForbiddenToast.jsx
import { useEffect, useState } from 'react';

export default function ForbiddenToast() {
  const [message, setMessage] = useState('');
  useEffect(() => {
    const onForbidden = (e) => {
      setMessage(e.detail);
      setTimeout(() => setMessage(''), 4000);
    };
    window.addEventListener('shopease:forbidden', onForbidden);
    return () => window.removeEventListener('shopease:forbidden', onForbidden);
  }, []);
  return message ? <div className="toast toast-warning">{message}</div> : null;
}

The Complete Picture

SituationServerReact
No token on a protected URL401 "Authentication required"Redirect to login
Access token expired401 "Access token expired"Refresh silently, retry the request
Refresh token expired or reused401 on /auth/refreshRedirect to login with "session expired"
Tampered token401 "Invalid access token"Refresh fails too, redirect to login
Wrong role or not the owner403 "You do not have permission..."Show a toast, stay logged in
Missing CSRF token403 "Invalid or missing CSRF token"Bug in the client: check withXSRFToken

Tip: Log every 401 and 403 on the server with the user, IP and path (never the token). A burst of 403s from one account is often someone probing other users' order ids.