Teams 会议流水线会使用 Microsoft Graph 读取会议转录、录制文件和相关 artifacts,并采用 app-only(daemon)认证 —— 不需要用户登录,也不需要每次会议进行交互式授权。这需要一个 Azure AD 应用注册,并授予已由管理员同意的 application permissions。
本指南将介绍:
- 创建 app registration
- 创建 client secret
- 授予流水线所需的 Graph API permissions
- 对这些 permissions 进行管理员同意
- (可选)使用 Application Access Policy 将 app 限定到特定用户
你需要 tenant admin 权限(或由管理员代表你授予同意)才能完成这一步。请保存你收集到的值 —— 它们最终会写入 ~/.hermes/.env。
- 一个 Microsoft 365 tenant,并且拥有会生成会议转录和录制文件的 Teams Premium 或 Teams licenses
- 拥有 Azure portal(
entra.microsoft.com)的管理员访问权限 - 一个公网可访问的 HTTPS endpoint,用于 Graph change notifications(稍后会在 webhook listener 步骤中设置)
步骤 1:创建 App Registration
Section titled “步骤 1:创建 App Registration”-
以 tenant admin 身份登录
entra.microsoft.com。 -
导航到 Identity → Applications → App registrations。
-
点击 New registration。
-
填写:
- Name:
Hermes Teams Meeting Pipeline(或任何你能识别的名称)。 - Supported account types:Accounts in this organizational directory only(Single tenant)。
- Redirect URI:留空 —— app-only auth 不需要它。
- Name:
-
点击 Register。
你会进入该 app 的 overview 页面。复制两个值:
- Application(client)ID →
MSGRAPH_CLIENT_ID - Directory(tenant)ID →
MSGRAPH_TENANT_ID
步骤 2:创建 Client Secret
Section titled “步骤 2:创建 Client Secret”- 在左侧导航中打开 Certificates & secrets。
- 点击 New client secret。
- Description:
hermes-graph-secret。Expires:选择符合你轮换策略的值(通常为 6–24 个月)。 - 点击 Add。
- 立即复制 Value 列 —— 它只会显示一次。这个值就是
MSGRAPH_CLIENT_SECRET。
Secret ID 列不是 secret。你需要的是 Value 列。
步骤 3:授予 Graph API Permissions
Section titled “步骤 3:授予 Graph API Permissions”该 pipeline 使用一组最小可行的 application permissions。只添加你需要的权限;每增加一个权限,都会扩大该 app 可在整个 tenant 范围内读取的内容。
- 在左侧导航中打开 API permissions。
- 点击 Add a permission → Microsoft Graph → Application permissions。
- 根据你希望 pipeline 执行的操作,添加下表中的相应 permissions。
- 添加后,点击 Grant admin consent for
<your tenant>。每个 permission 的 Status 列都应该变成绿色勾选状态。
用于 transcript-first summaries 的必需权限
Section titled “用于 transcript-first summaries 的必需权限”| Permission | 它允许 app 做什么 |
|---|---|
OnlineMeetings.Read.All | 读取 Teams online meeting metadata(主题、参与者、join URL)。 |
OnlineMeetingTranscript.Read.All | 读取 Teams 生成的 meeting transcripts。 |
用于 recording fallback 的必需权限(当 transcript 不可用时)
Section titled “用于 recording fallback 的必需权限(当 transcript 不可用时)”| Permission | 它允许 app 做什么 |
|---|---|
OnlineMeetingRecording.Read.All | 下载 Teams meeting recordings,用于离线 STT 处理。 |
CallRecords.Read.All | 当只知道 join URL 时,通过 call records 解析 meetings。 |
用于 outbound summary delivery 的必需权限(仅 Graph 模式)
Section titled “用于 outbound summary delivery 的必需权限(仅 Graph 模式)”如果 platforms.teams.extra.delivery_mode 是 graph,pipeline 会通过 Graph API 将 summaries 发布到 Teams channel 或 chat 中。如果你使用 incoming_webhook delivery mode,请跳过这些权限。
| Permission | 它允许 app 做什么 |
|---|---|
ChannelMessage.Send | 代表 app 向 Teams channels 发布消息。 |
Chat.ReadWrite.All | 向 1:1 和 group chats 发布消息(仅当你将 chat_id 设置为 delivery target 时)。 |
OnlineMeetings.ReadWrite.All/Chat.ReadWritewithout.All—— 比 pipeline 需要的权限更宽泛。- Delegated permissions —— pipeline 使用 app-only(client-credentials)flow;delegated permissions 如果没有用户登录将无法工作。
步骤 4:(推荐)使用 Application Access Policy 限定 App 范围
Section titled “步骤 4:(推荐)使用 Application Access Policy 限定 App 范围”默认情况下,像 OnlineMeetings.Read.All 这样的 application permissions 会授予 app 访问 tenant 中每个会议的权限。对于合作伙伴演示和开发 tenant 来说,这没问题;但对于生产环境,你几乎肯定会希望限制该 app 可以读取哪些用户的会议。
Microsoft 为 Teams 提供了 Application Access Policies,正是用于这个场景。该 policy 只能通过 PowerShell 管理;portal 中没有 UI。
在已安装并连接 MicrosoftTeams module 的管理员 PowerShell 中执行(Connect-MicrosoftTeams):
# Create a policy scoped to the Hermes appNew-CsApplicationAccessPolicy ` -Identity "Hermes-Meeting-Pipeline-Policy" ` -AppIds "<MSGRAPH_CLIENT_ID>" ` -Description "Restrict Hermes meeting pipeline to allow-listed users"
# Grant the policy to specific users whose meetings the pipeline may readGrant-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>"如果没有该 policy,任何用户的会议都可以被读取 —— 这正是该 permission 在技术上授予的权限。生产 tenant 中不要跳过这一步。
步骤 5:将凭证写入你的 Env 文件
Section titled “步骤 5:将凭证写入你的 Env 文件”将你收集到的三个值放入 ~/.hermes/.env:
MSGRAPH_TENANT_ID=<directory-tenant-id>MSGRAPH_CLIENT_ID=<application-client-id>MSGRAPH_CLIENT_SECRET=<client-secret-value>设置文件权限,确保只有你能读取 secret:
chmod 600 ~/.hermes/.env步骤 6:验证 Token Flow
Section titled “步骤 6:验证 Token Flow”Hermes 随附了一个 Graph auth smoke-test。在你的 Hermes 安装环境中运行:
python -c "import asynciofrom tools.microsoft_graph_auth import MicrosoftGraphTokenProviderprovider = MicrosoftGraphTokenProvider.from_env()token = asyncio.run(provider.get_access_token())print('Token acquired, length:', len(token))print(provider.inspect_token_health())"成功运行会打印一个很长的 token 字符串,以及一个 health dict,其中显示 cached: True,并且 expires_in_seconds 值接近 3600。失败时会产生 MicrosoftGraphTokenError,其中包含 Azure error code —— 最常见的是:
| Azure error | 含义 | 修复 |
|---|---|---|
AADSTS7000215: Invalid client secret | Secret value 不匹配或已过期。 | 在步骤 2 中生成新的 secret;更新 .env。 |
AADSTS700016: Application not found | MSGRAPH_CLIENT_ID 错误或 tenant 错误。 | 仔细检查步骤 1 中的值是否来自同一个 app。 |
AADSTS90002: Tenant not found | MSGRAPH_TENANT_ID 有拼写错误。 | 从 app overview 重新复制 Directory(tenant)ID。 |
call time 出现 insufficient_claims(不是 token time) | Token 能获取,但 Graph 返回 401/403。 | 你跳过了步骤 3 的 admin-consent,或者添加了 permissions 但没有重新 consent。回到 API permissions,并再次点击 Grant admin consent。 |
轮换 Client Secret
Section titled “轮换 Client Secret”Azure client secrets 有硬性过期时间。在你的 secret 过期前:
- 创建第二个 client secret(步骤 2),不要删除第一个。
- 用新值更新
~/.hermes/.env中的MSGRAPH_CLIENT_SECRET。 - 重启 gateway,让新 secret 生效:
hermes gateway restart。 - 使用上面的 smoke test 进行验证。
- 从 Azure portal 删除旧 secret。
当凭证验证正常后,继续:
- Webhook listener setup —— 启动接收 Graph change notifications 的
msgraph_webhookgateway platform。 - Pipeline configuration —— 配置 Teams meeting pipeline runtime 和 operator CLI。
- Outbound delivery —— 将 summaries 发回 Teams channel 或 chat。
这些页面会与添加对应 runtime 的 PR 一起发布。此凭证设置是一个独立前置条件,可以提前安全完成。