Skip to content

JWT и сервисная авторизация

VideoGrace использует bearer-token модель для всех runtime-каналов. CommandLoop выполняет первичную авторизацию, а затем тот же access_token используется для BlobChannel, WSMedia и REST API.

Runtime flow

sequenceDiagram
    participant Client
    participant Core as VideoGrace Server
    participant DB
    participant Media as Blob/WSMedia/API

    Client->>Core: connect_request(login/password)
    Core->>DB: load user + grants
    Core-->>Client: connect_response(access_token, refresh_token)
    Client->>Media: Authorization/connect_request access_token
    Media->>Core: validate token
    Core-->>Media: client_id + grants
    Client->>Core: POST /api/v1.0?auth_refresh
    Core->>DB: validate refresh token hash
    Core-->>Client: new access_token

Если задан VG_JWT_SECRET или [Auth] JwtSecret, access_token выпускается как JWT HS256. Если секрет не задан, сервер может работать в legacy-режиме с opaque token, но новый код не должен зависеть от этого режима.

Access JWT

JWT содержит только данные, нужные для быстрой авторизации:

Claim Значение
iss VideoGrace.
aud videograce.
typ access.
sub client_id.
login Логин пользователя.
name Отображаемое имя.
grants Битовая маска прав.
scope Каналы и API scopes.
jti ID токена для точечного revoke.
iat / exp Время выпуска и истечения.

Проверка JWT включает:

  • разбор трех частей JWT;
  • проверку alg=HS256;
  • HMAC-SHA256 подпись через серверный secret;
  • проверку aud, typ, exp;
  • проверку jti по таблице jwt_revoked;
  • загрузку актуального пользователя из БД по sub или login.

Клиентам не нужно читать claims. Для клиента token остается непрозрачной строкой.

Refresh token

refresh_token - случайный секрет, не JWT. Сервер хранит в БД только HMAC-хеш refresh token и TTL. Это позволяет:

  • не хранить access JWT в БД;
  • продлевать пользовательскую сессию без повторного пароля;
  • отозвать refresh token через удаление/деактивацию записи;
  • не раскрывать пароль сервисам и браузерным каналам.

REST endpoint:

POST /api/v1.0?auth_refresh
Content-Type: application/json

{
  "refresh_token": "..."
}

Ответ:

{
  "result": 200,
  "access_token": "...",
  "token_type": "Bearer"
}

Service accounts

Сервисные процессы не должны хранить пользовательские пароли. Для production используется таблица service_accounts: она связывает имя сервиса с обычным client_id, grants которого уже настроены в VideoGrace.

Типовой пример:

insert into service_accounts
  (name, client_id, scopes, enabled, created_at)
values
  ('transcriber', 228800001, '["conference:join","media:render","chat:write"]', 1, strftime('%s','now'));

Когда администратор отправляет CAN job transcriber.start без payload.auth, core выпускает короткий access JWT для service account и добавляет его в job payload. Worker получает задание уже с bearer token и подключается к CommandLoop стандартным путем.

Инварианты безопасности

  • JWT-secret должен быть серверным секретом и не должен попадать в клиентский bundle.
  • Refresh token нельзя передавать в media/blob/CAN worker как access token.
  • CAN service token авторизует подключение worker'а к /can, но не дает пользовательских grants.
  • Service account должен быть отдельным пользователем с минимально нужными правами.
  • Для точечного отзыва access JWT используйте jti и таблицу jwt_revoked; для полного сброса сессий меняйте JwtSecret.