cooldownDuration и cacheMaxAge в createRemoteJWKSet

createRemoteJWKSet возвращает функцию, которая автоматически загружает и кэширует JWKS (JSON Web Key Set) из удалённого источника. Это ключевой механизм в библиотеке Jose для проверки JWT, подписанных асимметричными алгоритмами (RS256, ES256 и др.), где публичные ключи публикуются через endpoint, например https://issuer/.well-known/jwks.json.

Внутреннее поведение опирается на кэширование и контроль частоты запросов к удалённому серверу. Два параметра, которые определяют стабильность и производительность работы — cacheMaxAge и cooldownDuration.


При первом запросе ключей происходит HTTP-запрос к JWKS endpoint. Ответ сохраняется в памяти процесса и используется для всех последующих проверок JWT без повторного обращения к сети.

Кэш не является статичным: он имеет срок актуальности, после которого библиотека инициирует обновление ключей.


cacheMaxAge

cacheMaxAge определяет максимальный возраст кэшированных ключей в миллисекундах, после которого данные считаются устаревшими и подлежат обновлению при следующей необходимости валидации токена.

Поведение

  • Пока время жизни кэша не истекло — JWKS берётся из памяти
  • После истечения срока — инициируется повторная загрузка JWKS
  • Обновление происходит лениво, только при следующей проверке JWT

Практический смысл

Этот параметр балансирует между:

  • частотой сетевых запросов
  • актуальностью ключей

Слишком большое значение:

  • снижает нагрузку на сеть
  • но увеличивает риск использования устаревших ключей при ротации

Слишком маленькое значение:

  • увеличивает количество HTTP-запросов
  • может создавать лишнюю нагрузку на identity provider

Типичные сценарии настройки

  • системы с редкой ротацией ключей: увеличенное значение cacheMaxAge
  • среды с высокой безопасностью и частой ротацией: уменьшенное значение
  • production с балансом: средние значения, зависящие от SLA провайдера идентификации

cooldownDuration

cooldownDuration управляет поведением после неудачной попытки загрузки JWKS.

Основной смысл

Если запрос к JWKS endpoint завершился ошибкой (сетевой сбой, 5xx, таймаут), библиотека не будет повторять запрос немедленно. Вместо этого вводится “период охлаждения”.

Поведение

  • при ошибке загрузки JWKS фиксируется состояние неуспешного запроса
  • последующие попытки в течение cooldownDuration не инициируют новый HTTP-запрос
  • вместо этого используются ранее закэшированные ключи (если они есть)

Зачем это нужно

Без механизма охлаждения возможен сценарий:

  • JWKS endpoint временно недоступен
  • система валидирует множество JWT
  • каждый запрос вызывает повторный HTTP fetch
  • создаётся эффект лавины запросов (retry storm)

cooldownDuration предотвращает этот эффект, ограничивая частоту повторных попыток.

Последствия настройки

Слишком маленькое значение:

  • повышенная нагрузка на JWKS сервер при сбоях
  • риск каскадных ошибок

Слишком большое значение:

  • дольше используется устаревший или отсутствующий JWKS
  • возможны временные проблемы с валидацией токенов после восстановления сервиса

Взаимодействие cacheMaxAge и cooldownDuration

Оба параметра влияют на разные аспекты жизненного цикла ключей:

  • cacheMaxAge управляет плановым обновлением
  • cooldownDuration управляет аварийным поведением

Их совместная работа формирует устойчивую модель:

  1. В нормальном режиме ключи обновляются по истечении cacheMaxAge
  2. При сбоях обновление блокируется на cooldownDuration
  3. До восстановления используются ранее загруженные ключи

Поведение при ротации ключей

В сценарии смены ключей у провайдера идентификации:

  • новый ключ добавляется в JWKS
  • старый может оставаться активным некоторое время
  • кэш должен своевременно обновиться через cacheMaxAge

Если cacheMaxAge слишком велик, возможна ситуация:

  • новый ключ уже используется для подписи
  • старый кэш не содержит его
  • валидация начинает падать до обновления кэша

Пример конфигурации

import { createRemoteJWKSet } from 'jose'

const JWKS = createRemoteJWKSet(
  new URL('https://issuer.example.com/.well-known/jwks.json'),
  {
    cacheMaxAge: 5 * 60 * 1000,
    cooldownDuration: 30 * 1000
  }
)

В данном случае:

  • кэш живёт 5 минут
  • при ошибке загрузки повторная попытка блокируется на 30 секунд

Особенности реализации в рантайме

  • кэш хранится в памяти процесса Node.js
  • каждый instance приложения имеет собственный кэш
  • при горизонтальном масштабировании (несколько серверов) кэш не разделяется
  • обновление JWKS не синхронизируется между инстансами

Ошибки, связанные с неправильной настройкой

Частые повторные запросы JWKS

Причина:

  • слишком маленький cacheMaxAge
  • отсутствие эффективного кэширования в приложении

Массовые сбои при временной недоступности провайдера

Причина:

  • cooldownDuration равен нулю или слишком мал
  • система не защищена от retry storm

Задержка принятия новых ключей

Причина:

  • cacheMaxAge слишком большой
  • обновлённые ключи не подхватываются вовремя

Практика балансировки параметров

При настройке учитываются:

  • стабильность JWKS endpoint
  • частота ротации ключей у identity provider
  • критичность системы авторизации
  • допустимая задержка обновления ключей
  • ожидаемая нагрузка на сервис идентификации

В системах с высокой нагрузкой предпочтение отдаётся снижению количества сетевых запросов, в системах с высокими требованиями безопасности — более агрессивному обновлению JWKS.


Сценарий деградации и восстановление

При временном отказе JWKS endpoint поведение определяется связкой параметров:

  • первый сбой вызывает переход в состояние cooldown
  • повторные попытки блокируются
  • при наличии старого кэша продолжает использоваться предыдущий JWKS
  • после истечения cooldownDuration выполняется новая попытка загрузки
  • при успешном ответе кэш обновляется и цикл нормализуется