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.