Регистрация приложения Microsoft Graph

Конвейер обработки Teams-встреч читает транскрипты, записи и связанные артефакты из Microsoft Graph с использованием app-only (daemon) аутентификации — без входа пользователя, без интерактивного согласия на каждую встречу. Для этого нужна регистрация Azure AD приложения с разрешениями уровня приложения, на которые дал согласие администратор.

Этот гайд охватывает:

  1. Создание регистрации приложения
  2. Создание секрета клиента
  3. Предоставление разрешений Graph API, которые нужны конвейеру
  4. Административное согласие на эти разрешения
  5. (Необязательно) Ограничение приложения конкретными пользователями через Application Access Policy

Для завершения вам понадобятся права администратора тенанта (или администратор, который даст согласие за вас). Сохраните значения, которые собираете — в конце они идут в ~/.hermes/.env.

Требования

  • Тенант Microsoft 365 с лицензиями Teams Premium или Teams, генерирующими транскрипты и записи встреч
  • Административный доступ к Azure Portal на entra.microsoft.com
  • Публично доступный HTTPS-эндпоинт для уведомлений об изменениях Graph (настраивается позже, на шаге webhook listener)

Шаг 1: Создание регистрации приложения

  1. Войдите на entra.microsoft.com как администратор тенанта.
  2. Перейдите в Identity → Applications → App registrations.
  3. Нажмите New registration.
  4. Заполните:
    • Name: Hermes Teams Meeting Pipeline (или любое имя, которое вы узнаете).
    • Supported account types: Accounts in this organizational directory only (Single tenant).
    • Redirect URI: оставьте пустым — для app-only аутентификации не нужен.
  5. Нажмите Register.

Вы попадёте на страницу обзора приложения. Скопируйте два значения:

  • Application (client) IDMSGRAPH_CLIENT_ID
  • Directory (tenant) IDMSGRAPH_TENANT_ID

Шаг 2: Создание секрета клиента

  1. В левой навигации откройте Certificates & secrets.
  2. Нажмите New client secret.
  3. Description: hermes-graph-secret. Expires: выберите значение, соответствующее вашей политике ротации (обычно 6–24 месяца).
  4. Нажмите Add.
  5. Немедленно скопируйте значение в столбце Value — оно показывается только один раз. Это и есть MSGRAPH_CLIENT_SECRET.

Столбец Secret ID — не секрет. Нужен столбец Value.

Шаг 3: Предоставление разрешений Graph API

Конвейер использует минимально необходимый набор разрешений уровня приложения. Добавляйте только то, что нужно: каждое разрешение расширяет доступ приложения ко всему тенанту.

  1. В левой навигации откройте API permissions.
  2. Нажмите Add a permissionMicrosoft GraphApplication permissions.
  3. Добавьте разрешения из таблицы ниже, соответствующие тому, что должен делать конвейер.
  4. После добавления нажмите Grant admin consent for <ваш тенант>. Столбец Status должен смениться на зелёную галочку для каждого разрешения.

Необходимо для резюме на основе транскрипта

РазрешениеЧто позволяет приложению
OnlineMeetings.Read.AllЧитать метаданные Teams онлайн-встреч (тема, участники, ссылка на подключение).
OnlineMeetingTranscript.Read.AllЧитать транскрипты встреч, созданные Teams.

Необходимо для резервного варианта через запись (когда транскрипт недоступен)

РазрешениеЧто позволяет приложению
OnlineMeetingRecording.Read.AllСкачивать записи Teams-встреч для офлайн-транскрибации.
CallRecords.Read.AllРазрешать встречи из записей звонков, когда известна только ссылка на подключение.

Необходимо для доставки резюме (только режим Graph)

Если platforms.teams.extra.delivery_mode равно graph, конвейер публикует резюме в Teams-канал или чат через Graph API. Пропустите, если используете режим доставки incoming_webhook.

РазрешениеЧто позволяет приложению
ChannelMessage.SendПубликовать сообщения в Teams-каналы от имени приложения.
Chat.ReadWrite.AllПубликовать сообщения в личные и групповые чаты (только если chat_id задан как цель доставки).

Не рекомендуется

  • OnlineMeetings.ReadWrite.All / Chat.ReadWrite без .All — шире, чем нужно конвейеру.
  • Делегированные разрешения — конвейер использует app-only (client-credentials) поток; делегированные разрешения не работают без входа пользователя.

Шаг 4: (Рекомендуется) Ограничение приложения через Application Access Policy

По умолчанию разрешения уровня приложения вроде OnlineMeetings.Read.All дают доступ ко всем встречам в тенанте. Для партнёрских демо и dev-тенантов это нормально; в продакшене почти наверняка нужно ограничить, чьи встречи может читать приложение.

Именно для этого Microsoft предоставляет Application Access Policies для Teams. Политика управляется только через PowerShell — интерфейса в Portal нет.

Из PowerShell администратора с установленным и подключённым модулем MicrosoftTeams (Connect-MicrosoftTeams):

# Создаём политику для приложения Hermes
New-CsApplicationAccessPolicy `
  -Identity "Hermes-Meeting-Pipeline-Policy" `
  -AppIds "<MSGRAPH_CLIENT_ID>" `
  -Description "Restrict Hermes meeting pipeline to allow-listed users"

# Выдаём политику конкретным пользователям, чьи встречи может читать конвейер
Grant-CsApplicationAccessPolicy `
  -PolicyName "Hermes-Meeting-Pipeline-Policy" `
  -Identity "alice@example.com"

Grant-CsApplicationAccessPolicy `
  -PolicyName "Hermes-Meeting-Pipeline-Policy" `
  -Identity "bob@example.com"

После предоставления распространение может занять до 30 минут. Проверьте командой:

Test-CsApplicationAccessPolicy -Identity "alice@example.com" -AppId "<MSGRAPH_CLIENT_ID>"

Без политики любые встречи пользователей доступны для чтения — именно это технически даёт разрешение. Не пропускайте этот шаг в продакшеновом тенанте.

Шаг 5: Запись учётных данных в env-файл

Запишите три собранных значения в ~/.hermes/.env:

MSGRAPH_TENANT_ID=<directory-tenant-id>
MSGRAPH_CLIENT_ID=<application-client-id>
MSGRAPH_CLIENT_SECRET=<client-secret-value>

Установите права на файл, чтобы только вы могли читать секрет:

chmod 600 ~/.hermes/.env

Шаг 6: Проверка токен-потока

Hermes поставляется с дымовым тестом аутентификации Graph. Из установленного Hermes:

python -c "
import asyncio
from tools.microsoft_graph_auth import MicrosoftGraphTokenProvider
provider = MicrosoftGraphTokenProvider.from_env()
token = asyncio.run(provider.get_access_token())
print('Token acquired, length:', len(token))
print(provider.inspect_token_health())
"

Успешный запуск печатает длинную строку токена и словарь состояния с cached: True и значением expires_in_seconds около 3600. При ошибках выводится MicrosoftGraphTokenError с кодом ошибки Azure. Самые распространённые:

Ошибка AzureЗначениеРешение
AADSTS7000215: Invalid client secretЗначение секрета не совпадает или истекло.Создайте новый секрет на шаге 2; обновите .env.
AADSTS700016: Application not foundНеверный MSGRAPH_CLIENT_ID или неверный тенант.Убедитесь, что значения из шага 1 взяты из одного и того же приложения.
AADSTS90002: Tenant not foundОпечатка в MSGRAPH_TENANT_ID.Снова скопируйте Directory (tenant) ID со страницы обзора приложения.
insufficient_claims при вызове (не при получении токена)Токен получен, но Graph возвращает 401/403.Вы пропустили административное согласие на шаге 3 или добавили разрешения, но не дали согласие повторно. Вернитесь в API permissions и снова нажмите Grant admin consent.

Ротация секрета клиента

У секретов клиента Azure есть жёсткий срок действия. Перед истечением:

  1. Создайте второй секрет клиента на шаге 2, не удаляя первый.
  2. Обновите MSGRAPH_CLIENT_SECRET в ~/.hermes/.env новым значением.
  3. Перезапустите шлюз, чтобы подхватить новый секрет: hermes gateway restart.
  4. Проверьте с помощью дымового теста выше.
  5. Удалите старый секрет из Azure Portal.

Следующие шаги

Когда учётные данные успешно прошли проверку, продолжайте:

  • Настройка webhook listener — запустите платформу шлюза msgraph_webhook, которая получает уведомления об изменениях от Graph.
  • Конфигурация конвейера — настройте среду выполнения конвейера Teams-встреч и CLI оператора.
  • Исходящая доставка — настройте отправку резюме в Teams-канал или чат.

Эти страницы появятся вместе с PR, добавляющими соответствующее время выполнения. Настройка учётных данных — самостоятельный шаг и безопасна для выполнения заранее.

ESC