Метод POST /api/v1/auth/refresh

Документация API: Фоновое обновление сессии (Refresh Token) с бесшовным перевыпуском Multi-Tenancy JWT Claims

Published

July 2, 2026

WarningОграничение публичной документации

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

  • Полная спецификация метода: Будет доступна только во внутреннем контуре разработки (Confluence / Swagger Enterprise).

1 Функциональное назначение

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

В рамках микросервисной архитектуры этот эндпоинт решает инфраструктурные задачи:

  1. “Interceptor” т.н. “перехватчик”: Метод вызывается сетевым слоем приложения (APP) строго в фоновом режиме, когда шлюз возвращает ошибку HTTP 401 Unauthorized на любой транзакционный запрос.
  2. Бесшовный перевыпуск контекста: Проверяет долгоживущий Refresh Token по базе сессий и генерирует новый короткоживущий Access Token (JWT), сохраняя актуальные JWT Private Claims home_group_id, account_type и user_id. Это гарантирует, что фоновые процессы сокетов и транзакции не прервутся для пользователя.
  3. Механизм обновления токенов (Refresh Token Rotation): Для защиты от компрометации, при каждом вызове старый Refresh-токен отзывается, а клиенту выдается новая пара токенов, что предотвращает атаки типа Replay Attack.

2 Протокол взаимодействия (HTTP Контракт)

  • Метод: POST
  • Маршрут: /api/v1/auth/refresh
  • Формат данных: application/json

2.1 Спецификация заголовков (HTTP Headers)

Заголовок Обязательный Описание Пример значения
Content-Type Да Указывает на передачу строго типизированного JSON-пакета application/json
X-Request-ID Да Сквозной ID запроса для трассировки фоновой ротации сессии req-auth-ref-22aa

2.2 Спецификация тела запроса (Request Body)

В соответствии с требованиями безопасности, Refresh-токен передается в теле JSON-запроса (или извлекается из защищенных HttpOnly Cookies в зависимости от конфигурации окружения).

Поле Тип Обязательный Описание Пример значения
refresh_token String Да Долгоживущий токен обновления, выданный при входе в систему ref-token-xyz789...

2.2.1 Пример сырого JSON-запроса (Payload):

{
  "refresh_token": "ref-token-xyz789_v1_signature..."
}

2.3 Спецификация успешного ответа (Response Body)

2.3.1 HTTP 200 OK

Возвращается при успешной валидации сессии. Выдается обновленный JWT-токен.

{
  "status": "success",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3UrODgyMiIsImhvbWVfZ3JvdXBfaWQiOiJncm91cC03NzItYWxwaGEiLCJhY2NvdW50X3R5cCI6IkhPTUUiLCJleHAiOjE3ODMzMTMyMDB9.new_signature...",
  "expires_in": 3600
}

3 Диаграмма последовательности (Mermaid)

На диаграмме представлена логика работы “перехватчика” (Interceptor) при фоновом обновлении токенов. Сервис Auth проверяет refresh_token по базе активных сессий, выполняет обновление, отзывает старый ключ и выпускает новый JWT с сохранением JWT Private Claims.

sequenceDiagram
    autonumber
    
    actor App as APP (Мобильное приложение)
    participant Nginx as Nginx Proxy
    participant GW as GATEWAY (backend-api)
    participant Auth as AUTH (auth-service)
    participant Redis as REDIS (Token Blacklist)
    participant DB as DB_AUTH (PostgreSQL)

    App->>Nginx: Шаг 1: POST /api/v1/auth/refresh (refresh_token)
    activate Nginx
    Nginx->>GW: Шаг 2: POST /backend-api/v1/auth/refresh
    activate GW
    GW->>Auth: Шаг 3: gRPC: VerifyAndRotate(RefreshRequest)
    activate Auth
    
    Auth->>Redis: Шаг 4: Redis.EXISTS(revoked_refresh)
    activate Redis
    note over Auth, Redis: При падении Redis:<br/>Fail-Close -> Аварийный выход HTTP 503
    Redis-->>Auth: Шаг 5: Токен НЕ найден в черном списке
    deactivate Redis
    
    Auth->>DB: Шаг 6: SQL SELECT is_revoked FROM user_sessions...
    activate DB
    DB-->>Auth: Токен валиден, срок не истек
    deactivate DB
    
    note over Auth: Шаг 7: Внутреннее действие:<br/>Атомарная деактивация старого<br/>и генерация нового токена
    
    Auth->>DB: Шаг 7 (продолжение): SQL UPDATE и INSERT сессий
    activate DB
    DB-->>Auth: Сессия обновлена
    deactivate DB
    
    Auth-->>GW: Шаг 8: gRPC: RotateResponse
    deactivate Auth
    GW-->>App: Шаг 9: HTTP 200 OK (new access, new refresh)
    deactivate GW
    deactivate Nginx
    
    note over App: Шаг 10: Внутренний метод<br/>SecureStorage.write(...) и разморозка очереди

Процесс ротации токенов (Refresh)

4 Расшифровка шагов

Шаг Действие Параметры / Запросы / DTO Ошибки (Исключения / Статусы)
Шаг 1 (App -> Nginx) При “протухании” Access-токена приложение фоново (Interceptor) отправляет запрос на ротацию сессии, передавая текущий Refresh-токен. HTTP POST /api/v1/auth/refresh
Payload (TokenRefreshRequestDTO):
{ "refresh_token": "def456..." }
DioException: send timeout
HTTP 400 Bad Request (пустой или невалидный по структуре токен ротации)
Шаг 2 (Nginx -> Gateway) Прокси-сервер выполняет базовую маршрутизацию входящего запроса на шлюз. HTTP POST /backend-api/v1/auth/refresh
Headers:
X-Request-ID: "trace-auth-lifecycle-uuid"
HTTP 502 Bad Gateway (контейнер backend-api недоступен)
HTTP 504 Gateway Timeout
Шаг 3 (Gateway -> Auth) API-шлюз обращается к контуру авторизации по gRPC-каналу для верификации и ротации токена. Протокол: gRPC
Метод: VerifyAndRotate(RefreshRequest)
Параметры: refresh_token
gRPC Status: UNAVAILABLE (сервис авторизации недоступен)
gRPC Status: DEADLINE_EXCEEDED (таймаут обработки криптографии)
Шаг 4 (Auth -> Redis) Сервис проверяет наличие хэша присланного Refresh-токена в черном списке отозванных токенов (Token Blacklist). Redis Команда:
EXISTS "revoked:refresh:hash_of_def456..."
Fail-Close Аварийный выход:
Redis.ConnectionError -> Перехват исключения на бэкенде и возврат HTTP 503 Service Unavailable
Шаг 5 (Redis -> Auth) Redis возвращает статус проверки, подтверждая, что токен отсутствует в черном списке. Ответ кэша: 0 (Токен НЕ найден в черном списке, проверка пройдена). Redis.TimeoutError: Command timed out
Шаг 6 (Auth -> DB_Auth) Сервис запрашивает из PostgreSQL статус сессии для валидации срока её действия и флага отзыва. SQL-запрос:
SELECT is_revoked, expires_at FROM user_sessions WHERE refresh_token_hash = 'hash...' LIMIT 1;
PostgreSQL Exception: ConnectionPoolTimeout
gRPC Status: UNAUTHENTICATED (сессия отозвана, просрочена или отсутствует в БД)
Шаг 7 (Auth -> Auth) Внутреннее действие: сервис проверяет подпись токена в памяти, отзывает старый ключ и генерирует новую пару JWT со старыми Claims. Внутренняя операция ротации токенов.
Сдвиг временного окна сессии на новый TTL.
JWT New Access Claims:
{ "sub": "usr-8822", "home_group_id": "group-772-alpha", "account_type": "HOME" }
CryptoException: TokenGenerationFailed (сбой генерации)
Шаг 7 (продолжение) (Auth -> DB_Auth) Сервис атомарно обновляет текущую сессию (помечая её старый токен отозванным) и выполняет новую запись сессии в БД. SQL-запросы (в рамках одной транзакции):
UPDATE user_sessions SET is_revoked = true WHERE refresh_token_hash = 'old_hash...';
INSERT INTO user_sessions (user_id, refresh_token_hash, expires_at) VALUES ('usr-8822', 'new_hash...', '2026-08-27');
PostgreSQL Exception: UniqueViolation
PostgreSQL Exception: TransactionAborted
Шаг 8 (Auth -> Gateway) Модуль сессий возвращает сформированную новую пару токенов по gRPC-каналу обратно на API-шлюз. Протокол: gRPC
Ответ: RotateResponse
Payload: access_token, refresh_token
gRPC Status: INTERNAL (ошибка сборки структуры сообщения)
Шаг 9 (Gateway -> App) Шлюз транслирует успешный HTTP-ответ 200 OK с новой парой токенов через Nginx на устройство. HTTP Статус на выходе Nginx: 200 OK
Response Body:
{ "status": "success", "token": "eyJhbGci...NEW_ACCESS", "refresh_token": "def456...NEW_REFRESH", "expires_in": 3600 }
DioException: receive timeout (пара токенов обновлена в бэкенде, но клиент потерял TCP-сессию из-за обрыва связи)
Шаг 10 (App -> App) Мобильное приложение перезаписывает токены в защищенном хранилище и возобновляет отправку ранее замороженных запросов. Внутренний метод: SecureStorage.write(...)
Запись в iOS Keychain или Android Keystore + разморозка очереди (Interceptor Queue).
SecureStorageException (ошибка стирания или записи ключей на смартфоне)