Files
transcriber/tasks/items/oidc-login.md
T
av c44f0e7582 HTTP API закрыт за вход через OIDC у Authelia
- шаг схемы закрывает поверхность, которую хранилище приносит открытой:
  собственную регистрацию, вход по паролю и одноразовый код — без этого
  закрытие приёма обходилось двумя запросами
- продление сессии выключено, срок семь суток: иначе отзыв доступа у
  провайдера до сервиса не доходит никогда
- файл записи отдаётся вошедшему по токену файла — пересмотр
  ADR-2026-08-12-file-link-open-but-not-logged
2026-08-12 17:44:22 +03:00

5.4 KiB

Пускать в приложение только после входа через OIDC

  • Тип: feature
  • Категория: Очередь
  • Зачем: HTTP API открыт наружу без аутентификации: любой из интернета заводит задачи за наши деньги и читает чужие расшифровки по идентификатору.
  • Теги: goal:multi-user

Двигает пункты 1 и 3 «Завершения» цели: неаутентифицированный запрос к записям не проходит ни к странице, ни к API; вход идёт через OIDC у Authelia, а выход из сессии работает.

Провайдер — Authelia по OIDC. Своей регистрации и своих паролей не делаем, это граница из паспорта. Разграничения записей по владельцу здесь ещё нет: после входа видно всё, что видно сейчас, — этим занимается record-ownership.

Ответ провайдера разбирает PocketBase, а не наш код — решено 2026-08-11 (adr). У её коллекции пользователей настраивается провайдер oidc с адресами Authelia, и учётные записи заводятся сами; проверено на версии 0.39.10, docs/research/pocketbase.md. Отсюда порядок: задача идёт после pocketbase-storage, до неё настраивать нечего.

Затрагивает

  • настройка провайдера oidc у коллекции пользователей PocketBase: адреса Authelia, идентификатор клиента, секрет, соответствие полей учётной записи;
  • эндпоинты входа и выхода, которые PocketBase приносит своими;
  • POST /api/audio и GET /api/status/:id — оба уходят за аутентификацию;
  • GET /health и GET /metrics — остаются открытыми и сессии не требуют;
  • хранение сессии: её ведёт PocketBase, и решить надо, чем она предъявляется приложению;
  • секция конфигурации под провайдера: адрес, идентификатор клиента, секрет;
  • docs/security.md — периметр меняется, и первая его строка перестаёт быть верной;
  • config.dist.toml и internal/config.

Критерии приёмки

  • Запрос к POST /api/audio и GET /api/status/:id без сессии получает отказ, а не заводит задачу и не отдаёт текст. Оракул — тест на обоих эндпоинтах без куки: код ответа 401 либо 302 на вход, тело без данных задачи. Тот же тест проверяет вторую сторону границы: GET /health и GET /metrics без куки отвечают 200.
  • Сессия переживает перезапуск приложения. Оракул — тест: запрос с прежней кукой после пересоздания сервера проходит.
  • Выход из сессии закрывает доступ. Оракул — тест: после выхода тот же запрос получает отказ.
  • Секрет провайдера не попадает ни в лог, ни в ответ. Оракул — тест на отсутствие значения секрета в записанном выводе логгера.
  • Первая строка docs/security.md описывает новый периметр. Оракул — task gate, шаг docs.py check.

Рамки

Владельца у записи здесь не заводим и выборку не сужаем: после входа видно столько же, сколько сейчас. Инвариант «бот отвечает только тем, кто в белом списке» не трогаем — он живёт до telegram-account-link. Панель администратора тоже не трогаем: наружу её закрывает Authelia на обратном прокси, а это работа выкладки.

GET /health и GET /metrics за аутентификацию не уходят — решено 2026-08-12. Сессии нет ни у пробы здоровья, ни у сборщика Prometheus, и вход по личным токенам эта задача не заводит. Наружу их закрывает то же правило обратного прокси, что и панель администратора, — работа выкладки. Пока правило не поставлено, /metrics отдаёт наружу объёмы работы сервиса: число задач, размеры и длительности записей; содержимого расшифровок в них нет.