Тестирование истечения срока токена

Модель жизненного цикла токена

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

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

  • идентификатор пользователя
  • временную метку создания
  • срок действия (TTL)
  • криптографическую подпись

При декодировании токена сервер сверяет текущую временную метку с параметром истечения и принимает решение о валидности.


Конфигурация времени жизни токена

В Iron-конфигурациях срок жизни токена задаётся через параметры шифрования сессии. Чаще всего используется подход, при котором TTL задаётся в миллисекундах или секундах.

Пример логической модели:

const sessionOptions = {
    ttl: 1000 * 60 * 15, // 15 минут
    encryptionKey: process.env.ENCRYPTION_KEY,
    algorithm: 'aes-256-gcm'
};

Ключевое поведение:

  • TTL применяется в момент создания токена
  • истечение рассчитывается относительно timestamp генерации
  • повторное использование старого токена блокируется

Механизм проверки истечения

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

Алгоритм проверки включает несколько этапов:

  1. Декодирование зашифрованного токена
  2. Проверка целостности подписи
  3. Извлечение временных меток
  4. Сравнение текущего времени с issuedAt + ttl

Логическая модель проверки:

function isTokenExpired(session) {
    const now = Date.now();
    return now > session.createdAt + session.ttl;
}

Если условие истинно, токен отклоняется до этапа бизнес-логики приложения.


Особенности тестирования истечения срока

Тестирование поведения истечения токена требует контролируемого управления временем. В отличие от обычных юнит-тестов, здесь критически важна возможность симуляции временных интервалов.

Используются следующие подходы:

  • мокирование системного времени
  • искусственное уменьшение TTL
  • ручная модификация timestamp в токене
  • использование таймеров с ускоренным временем выполнения

Мокирование времени

Наиболее распространённый способ тестирования основан на подмене глобального времени выполнения.

Пример с использованием Jest:

jest.useFakeTimers();

test('токен должен истечь', () => {
    const token = createSessionToken(user, { ttl: 1000 });

    jest.advanceTimersByTime(1500);

    const result = validateToken(token);

    expect(result).toBe(false);
});

Механика работы:

  • время системы фиксируется
  • таймеры управляются вручную
  • поведение TTL становится детерминированным

Тестирование через изменение TTL

Альтернативный подход основан на установке минимального времени жизни токена.

const token = createSessionToken(user, {
    ttl: 1 // 1 миллисекунда
});

setTimeout(() => {
    const isValid = validateToken(token);
    console.log(isValid); // ожидается false
}, 10);

Этот метод менее точный, но позволяет проверять реальные асинхронные сценарии.


Проверка устойчивости к часовому сдвигу

Отдельный класс тестов связан с проверкой поведения системы при несинхронизированном времени:

  • смещение системных часов вперёд
  • смещение назад
  • различия между сервером и клиентом

Типовой сценарий:

test('должен отклонять токен при значительном сдвиге времени', () => {
    const token = createSessionToken(user);

    mockSystemTime(Date.now() + 1000 * 60 * 60 * 24);

    const result = validateToken(token);

    expect(result).toBe(false);
});

Граничные случаи истечения

Особое внимание уделяется моменту перехода через границу TTL.

Проблемные зоны:

  • равенство текущего времени и времени истечения
  • задержки сетевых запросов
  • различия в таймзонах при распределённой архитектуре

Типовая проверка:

if (now >= expirationTime) {
    invalidateSession();
}

Использование >= вместо > предотвращает неконсистентность состояния.


Тестирование в распределённых системах

В системах с несколькими сервисами проверка истечения усложняется из-за рассинхронизации времени.

Используются дополнительные механизмы:

  • NTP-синхронизация серверов
  • передача времени создания токена через защищённый канал
  • централизованная проверка TTL

Тестовые сценарии включают имитацию задержек между сервисами и анализ поведения при частично просроченных токенах.


Отладка поведения истекших токенов

Для диагностики используются логические маркеры:

  • issuedAt
  • expiresAt
  • validatedAt

Пример логирования:

console.log({
    issuedAt: session.createdAt,
    expiresAt: session.createdAt + session.ttl,
    validatedAt: Date.now()
});

Это позволяет точно определить момент, в который токен становится недействительным.


Поведение при повторной проверке

После истечения срока токен не должен восстанавливаться даже при повторной валидации без повторной аутентификации.

Типичная ошибка реализации:

  • кэширование валидного состояния
  • отсутствие повторной проверки TTL при повторном запросе

Корректная модель всегда выполняет пересчёт времени на каждом запросе, без сохранения результата проверки валидности.