Refresh token

  • 1. Step

    Flow

    1. Login → receive access + refresh token.

    2. Store tokens in localStorage or httpOnly cookie.

    3. On 401 (access token expired) → send refresh token to /refresh.

    4. Update access token and retry the request.

    1. Store Tokens After Login

    
    
    const handleLogin = async () => {
      const res = await fetch('/api/login', {
        method: 'POST',
        body: JSON.stringify({ email, password }),
        headers: { 'Content-Type': 'application/json' }
      });
    
      if (res.ok) {
        const { accessToken, refreshToken } = await res.json();
        localStorage.setItem('accessToken', accessToken);
        localStorage.setItem('refreshToken', refreshToken);
      }
    };
    
    

    2. Create a Token Refresh Function

    auth.js

    
    
    export const refreshAccessToken = async () => {
      const refreshToken = localStorage.getItem('refreshToken');
      if (!refreshToken) return null;
    
      const res = await fetch('/api/refresh', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ refreshToken }),
      });
    
      if (!res.ok) {
        // Refresh token expired or invalid
        localStorage.removeItem('accessToken');
        localStorage.removeItem('refreshToken');
        window.location.href = '/login';
        return null;
      }
    
      const data = await res.json();
      localStorage.setItem('accessToken', data.accessToken);
      return data.accessToken;
    };
    
    
    

    3. Create a Fetch Wrapper with Auto-Retry

    api.js

    
    
    import { refreshAccessToken } from './auth';
    
    export const secureFetch = async (url, options = {}) => {
      let accessToken = localStorage.getItem('accessToken');
    
      const res = await fetch(url, {
        ...options,
        headers: {
          ...(options.headers || {}),
          'Authorization': `Bearer ${accessToken}`,
        },
      });
    
      if (res.status === 401) {
        // Try to refresh token
        accessToken = await refreshAccessToken();
        if (!accessToken) return res;
    
        // Retry original request with new token
        const retryRes = await fetch(url, {
          ...options,
          headers: {
            ...(options.headers || {}),
            'Authorization': `Bearer ${accessToken}`,
          },
        });
    
        return retryRes;
      }
    
      return res;
    };
    
    

    4. Use It in Your Components

    
      import { useEffect, useState } from 'react';
    import { secureFetch } from './api';
    
    const UserList = () => {
      const [users, setUsers] = useState([]);
    
      useEffect(() => {
        secureFetch('/api/users')
          .then(res => res.json())
          .then(data => setUsers(data))
          .catch(err => console.error(err));
      }, []);
    
      return (
        <ul>
          {users.map(user => (
            <li key={user.id}>{user.name}</li>
          ))}
        </ul>
      );
    };