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

Документация API: Деактивация сессии пользователя (Logout) с каскадной инвалидацией WebSocket-дескрипторов

Published

July 2, 2026

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

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

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

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

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

В рамках новой распределенной архитектуры метод POST /logout решает три ключевые задачи:

  1. Аннулирование долгоживущей сессии (Revocation): Переводит флаг is_revoked целевого refresh_token в состояние true в таблице user_sessions, полностью блокируя возможность фонового продления сессии через Dio Interceptor.
  2. Очистка ресурсов WebSocket-менеджера: Отправляет внутренний асинхронный сигнал в оперативную память шлюза, чтобы принудительно закрыть текущий активный WSS-стрим (/ws/push-stream/{id}) именно для этого девайса, предотвращая утечки памяти и отправку системных пушей на отключенное устройство.
  3. Безопасный сброс стейта UI: Служит триггером для мобильного приложения для полной очистки локальных хранилищ Secure Storage и переключения интерфейса на стартовый экран авторизации.

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

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

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

Заголовок Обязательный Описание Пример значения
Content-Type Да Указывает на передачу JSON-пакета application/json
Authorization Да Токен доступа (Access Token). Шлюз вычитывает user_id и home_group_id. Bearer eyJhbGciOiJIUzI1Ni...
X-Request-ID Да Сквозной ID запроса для трассировки сессии выхода из системы req-auth-out-77aa

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

В теле запроса клиент явно передает текущий валидный refresh_token, который подлежит удалению в базе данных.

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

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

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

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

На диаграмме представлена логика безопасного выхода из системы (POST /logout). Сервис Auth блокирует refresh_token в PostgreSQL, после чего шлюз обращается к своему пулу активных соединений и принудительно “тушит” WebSocket-стрим этого смартфона, освобождая оперативную память сервера.

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/logout (Bearer Access / Body Refresh)
    activate Nginx
    Nginx->>GW: Шаг 2: POST /backend-api/v1/auth/logout
    activate GW
    GW->>Auth: Шаг 3: gRPC: LogoutUser(LogoutRequest)
    activate Auth
    
    Auth->>Redis: Шаг 4: Redis.SET(blacklist:access, ex=TTL)
    activate Redis
    note over Auth, Redis: При падении Redis:<br/>Fail-Close -> Аварийный выход HTTP 503
    Redis-->>Auth: Токен успешно заблокирован в кэше
    deactivate Redis
    
    Auth->>DB: Шаг 5: SQL UPDATE user_sessions SET is_revoked = true...
    activate DB
    DB-->>Auth: Статус сессии обновлен в БД
    deactivate DB
    
    Auth-->>GW: Шаг 6: gRPC: LogoutResponse
    deactivate Auth
    GW-->>App: Шаг 7: HTTP 200 OK (status: success)
    deactivate GW
    deactivate Nginx
    
    note over App: Шаг 8: Внутренний метод<br/>SecureStorage.deleteAll() и редирект

Процесс безопасного выхода (Logout)

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

Шаг Действие Параметры / Запросы / DTO Ошибки (Исключения / Статусы)
Шаг 1 (App -> Nginx) Пользователь нажимает «Выйти». Клиент отправляет запрос, передавая Access Token в заголовке и текущий Refresh Token в теле для аннулирования. HTTP POST /api/v1/auth/logout
Headers: Authorization: Bearer <Access_JWT>
Payload (LogoutRequestDTO):
{ "refresh_token": "ref-token-xyz789_v1_signature..." }
DioException: send timeout
HTTP 401 Unauthorized (токен доступа изменен, подделан или отсутствует)
Шаг 2 (Nginx -> Gateway) Прокси-сервер транслирует команду на отзыв сессии на внутренний API-шлюз с сохранением заголовков. HTTP POST /backend-api/v1/auth/logout
Headers:
X-Request-ID: "req-auth-out-77aa", Authorization
HTTP 502 Bad Gateway (контейнер backend-api недоступен)
HTTP 504 Gateway Timeout
Шаг 3 (Gateway -> Auth) API-шлюз извлекает user_id и метаданные из токена и направляет gRPC-команду на принудительное аннулирование сессий в контур авторизации. Протокол: gRPC
Метод: LogoutUser(LogoutRequest)
Параметры: refresh_token, user_id
gRPC Status: UNAVAILABLE (сервис авторизации недоступен)
gRPC Status: INVALID_ARGUMENT
Шаг 4 (Auth -> Redis) Инвалидация через Блэклист: Оставшееся время жизни (Remaining TTL) Access-токена вычисляется в памяти сервиса, и токен вносится в Redis Blacklist. Redis Команда (Блокировка Access JWT):
SET "blacklist:access:eyJhbGci..." "revoked" EX 450
(Где 450 секунд — динамический остаток TTL токена в памяти)
Fail-Close Аварийный выход:
Redis.ConnectionError -> Перехват исключения на бэкенде и возврат HTTP 503 Service Unavailable
Шаг 5 (Redis -> Auth) Redis подтверждает успешную фиксацию и блокировку токена доступа в оперативной памяти кэша. Ответ кэша: Статус OK. Redis.TimeoutError: Command timed out
Шаг 5 (продолжение) (Auth -> DB_Auth) Сервис выполняет деактивацию сессии в PostgreSQL, переводя токен в состояние отозванного по его хэшу. SQL-запрос:
UPDATE user_sessions SET is_revoked = true WHERE refresh_token_hash = 'hash_of_token...' AND user_id = 'user-uuid';
PostgreSQL Exception: ConnectionPoolTimeout
PostgreSQL Exception: CommandTimeout
Подтверждение (DB_Auth -> Auth) База данных выполняет изменение статуса строки и подтверждает закрытие сессии. Ответ СУБД: Статус UPDATE 1 (успешно изменена 1 строка). PostgreSQL Exception: DatabaseIsShuttingDown
PostgreSQL Exception: TransactionAborted
Шаг 6 (Auth -> Gateway) Сервис авторизации возвращает успешный gRPC-ответ, подтверждая блокировку всех токенов сессии. Протокол: gRPC
Ответ: LogoutResponse
Payload: success: true
gRPC Status: INTERNAL (ошибка маршаллинга gRPC-сообщения)
Шаг 7 (Gateway -> App) Шлюз возвращает финальный успешный HTTP-статус через Nginx, подтверждая полное уничтожение сессии в экосистеме. HTTP Статус на выходе Nginx: 200 OK
Response Body:
{ "status": "success", "data": { "message": "SESSION_TERMINATED", "details": "Refresh token successfully revoked. Active WebSocket connection terminated clean.", "timestamp": "2026-07-02T02:20:00Z" } }
DioException: receive timeout (клиент потерял сеть в момент отправки финального ответа)
Шаг 8 (App -> App) Сброс стейта UI: Мобильное приложение полностью очищает локальное хранилище и переключает интерфейс на экран авторизации. Внутренний метод приложения:
SecureStorage.deleteAll() и мгновенный редирект пользователя на стартовый экран логина.
SecureStorageException (критическая ошибка очистки Keychain/Keystore на смартфоне)

5 Спецификация ответов сервера (Response Body) и ошибок

5.1 1. Успешный ответ (Success Response)

5.1.1 HTTP 200 OK (Ответ на Шаге 8)

Возвращается мобильному приложению после успешного коммита транзакции деактивации. В теле ответа фиксируется успешное удаление сессии.

  • Заголовки ответа (Response Headers):
    • Content-Type: application/json
  • Тело ответа (Response Body):
{
  "status": "success",
  "data": {
    "message": "SESSION_TERMINATED",
    "details": "Refresh token successfully revoked. Active WebSocket connection terminated clean.",
    "timestamp": "2026-07-02T02:20:00Z"
  }
}