← Назад к вопросам

Как понимаешь в какой момент нужно обновить токен?

1.7 Middle🔥 131 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое токен и почему его нужно обновлять?

Токен доступа (access token) — это криптографический ключ, который подтверждает личность пользователя и даёт ему права на выполнение определённых действий. Токены имеют время жизни (TTL — Time To Live), которое может быть от нескольких минут до нескольких часов. После истечения этого времени токен становится невалидным, и пользователь не сможет выполнять защищённые операции.

Обновление токена необходимо, чтобы пользователь оставался авторизованным без необходимости повторного входа. Вместо хранения долгоживущего токена (что снижает безопасность), используется пара: короткоживущий access token и долгоживущий refresh token.

Когда обновлять токен?

Проактивный подход (рекомендуется):

const useAuth = () => {
  const refreshInterval = useRef(null);
  
  useEffect(() => {
    const expiresIn = getTokenExpiration();
    const refreshTime = (expiresIn - 300) * 1000;
    
    refreshInterval.current = setTimeout(() => {
      refreshAccessToken();
    }, refreshTime);
    
    return () => clearTimeout(refreshInterval.current);
  }, []);
};

Реактивный подход (при ошибке):

const api = axios.create({...});

api.interceptors.response.use(
  response => response,
  async error => {
    if (error.response?.status === 401) {
      try {
        const newToken = await refreshAccessToken();
        error.config.headers.Authorization = `Bearer ${newToken}`;
        return api(error.config);
      } catch (err) {
        redirectToLogin();
        return Promise.reject(err);
      }
    }
    return Promise.reject(error);
  }
);

Практическая реализация в React

export const refreshAccessToken = async () => {
  const refreshToken = localStorage.getItem("refresh_token");
  
  if (!refreshToken) {
    throw new Error("No refresh token available");
  }
  
  const response = await fetch("/api/v1/auth/refresh", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ refresh_token: refreshToken }),
  });
  
  if (!response.ok) {
    localStorage.removeItem("access_token");
    localStorage.removeItem("refresh_token");
    window.location.href = "/login";
    throw new Error("Failed to refresh token");
  }
  
  const { access_token, expires_in } = await response.json();
  localStorage.setItem("access_token", access_token);
  localStorage.setItem("token_expires_at", Date.now() + expires_in * 1000);
  
  return access_token;
};

export const useAuth = () => {
  const [user, setUser] = useState(null);
  const refreshTimeoutRef = useRef(null);
  
  const scheduleTokenRefresh = useCallback((expiresIn) => {
    const refreshTime = (expiresIn - 60) * 1000;
    
    refreshTimeoutRef.current = setTimeout(async () => {
      try {
        await refreshAccessToken();
        const newExpiresIn = JSON.parse(
          atob(localStorage.getItem("access_token").split(".")[1])
        ).exp - Math.floor(Date.now() / 1000);
        scheduleTokenRefresh(newExpiresIn);
      } catch (error) {
        console.error("Token refresh failed:", error);
        setUser(null);
      }
    }, refreshTime);
  }, []);
  
  useEffect(() => {
    return () => clearTimeout(refreshTimeoutRef.current);
  }, []);
  
  return { user, scheduleTokenRefresh };
};

Хранение токенов: localStorage vs cookies

localStorage: просто, но уязвим для XSS атак. HttpOnly cookies: безопаснее (недоступны JavaScript), защищены от XSS, но требуют дополнительной настройки CSRF. Оптимально: хранить refresh token в HttpOnly cookie, access token в памяти или localStorage.