181 lines
8.3 KiB
Markdown
181 lines
8.3 KiB
Markdown
---
|
|
title: "Register a Microsoft Graph Application"
|
|
description: "Azure portal walkthrough for creating the app registration that powers the Teams meeting pipeline"
|
|
---
|
|
|
|
# Register a Microsoft Graph Application
|
|
|
|
The Teams meeting pipeline reads meeting transcripts, recordings, and related artifacts from Microsoft Graph using **app-only** (daemon) authentication — no user sign-in, no interactive consent per meeting. That requires an Azure AD application registration with admin-consented application permissions.
|
|
|
|
This guide walks through:
|
|
|
|
1. Creating the app registration
|
|
2. Creating a client secret
|
|
3. Granting the Graph API permissions the pipeline needs
|
|
4. Admin-consenting those permissions
|
|
5. (Optional) Scoping the app to specific users with an Application Access Policy
|
|
|
|
You need **tenant admin rights** (or an admin to grant consent on your behalf) to finish this. Bookmark the values you collect — they go into `~/.hermes/.env` at the end.
|
|
|
|
## Prerequisites
|
|
|
|
- A Microsoft 365 tenant with Teams Premium or Teams licenses that produce meeting transcripts and recordings
|
|
- Admin access to the Azure portal at [entra.microsoft.com](https://entra.microsoft.com)
|
|
- A publicly reachable HTTPS endpoint for Graph change notifications (set up later, in the webhook listener step)
|
|
|
|
## Step 1: Create the App Registration
|
|
|
|
1. Sign in to [entra.microsoft.com](https://entra.microsoft.com) as a tenant admin.
|
|
2. Navigate to **Identity → Applications → App registrations**.
|
|
3. Click **New registration**.
|
|
4. Fill in:
|
|
- **Name:** `Hermes Teams Meeting Pipeline` (or any name you'll recognize).
|
|
- **Supported account types:** *Accounts in this organizational directory only (Single tenant)*.
|
|
- **Redirect URI:** leave blank — app-only auth does not need one.
|
|
5. Click **Register**.
|
|
|
|
You'll land on the app's overview page. Copy two values:
|
|
|
|
- **Application (client) ID** → `MSGRAPH_CLIENT_ID`
|
|
- **Directory (tenant) ID** → `MSGRAPH_TENANT_ID`
|
|
|
|
## Step 2: Create a Client Secret
|
|
|
|
1. In the left nav, open **Certificates & secrets**.
|
|
2. Click **New client secret**.
|
|
3. **Description:** `hermes-graph-secret`. **Expires:** pick a value that matches your rotation policy (6-24 months is typical).
|
|
4. Click **Add**.
|
|
5. Copy the **Value** column immediately — it's only shown once. That value is `MSGRAPH_CLIENT_SECRET`.
|
|
|
|
> The **Secret ID** column is not the secret. You want the **Value** column.
|
|
|
|
## Step 3: Grant Graph API Permissions
|
|
|
|
The pipeline uses a minimum-viable set of application permissions. Add only what you need; each one widens what the app can read tenant-wide.
|
|
|
|
1. In the left nav, open **API permissions**.
|
|
2. Click **Add a permission** → **Microsoft Graph** → **Application permissions**.
|
|
3. Add the permissions from the table below that match what you want the pipeline to do.
|
|
4. After adding, click **Grant admin consent for `<your tenant>`**. The Status column should flip to a green checkmark for every permission.
|
|
|
|
### Required for transcript-first summaries
|
|
|
|
| Permission | What it lets the app do |
|
|
|------------|--------------------------|
|
|
| `OnlineMeetings.Read.All` | Read Teams online meeting metadata (subject, participants, join URL). |
|
|
| `OnlineMeetingTranscript.Read.All` | Read meeting transcripts generated by Teams. |
|
|
|
|
### Required for recording fallback (when a transcript is unavailable)
|
|
|
|
| Permission | What it lets the app do |
|
|
|------------|--------------------------|
|
|
| `OnlineMeetingRecording.Read.All` | Download Teams meeting recordings for offline STT processing. |
|
|
| `CallRecords.Read.All` | Resolve meetings from call records when only the join URL is known. |
|
|
|
|
### Required for outbound summary delivery (Graph mode only)
|
|
|
|
If `platforms.teams.extra.delivery_mode` is `graph`, the pipeline posts summaries into a Teams channel or chat via the Graph API. Skip these if you use `incoming_webhook` delivery mode instead.
|
|
|
|
| Permission | What it lets the app do |
|
|
|------------|--------------------------|
|
|
| `ChannelMessage.Send` | Post messages into Teams channels on behalf of the app. |
|
|
| `Chat.ReadWrite.All` | Post messages into 1:1 and group chats (only if you set `chat_id` as the delivery target). |
|
|
|
|
### Not recommended
|
|
|
|
- `OnlineMeetings.ReadWrite.All` / `Chat.ReadWrite` without `.All` — broader than the pipeline needs.
|
|
- Delegated permissions — the pipeline uses app-only (client-credentials) flow; delegated permissions won't work without user sign-in.
|
|
|
|
## Step 4: (Recommended) Scope the App with an Application Access Policy
|
|
|
|
By default, application permissions like `OnlineMeetings.Read.All` grant the app access to **every** meeting in the tenant. For partner demos and dev tenants that's fine; for production you almost certainly want to restrict which users' meetings the app can read.
|
|
|
|
Microsoft provides **Application Access Policies** for Teams exactly for this. The policy is a PowerShell-only surface; there's no portal UI for it.
|
|
|
|
From an admin PowerShell with the MicrosoftTeams module installed and connected (`Connect-MicrosoftTeams`):
|
|
|
|
```powershell
|
|
# Create a policy scoped to the Hermes app
|
|
New-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 read
|
|
Grant-CsApplicationAccessPolicy `
|
|
-PolicyName "Hermes-Meeting-Pipeline-Policy" `
|
|
-Identity "alice@example.com"
|
|
|
|
Grant-CsApplicationAccessPolicy `
|
|
-PolicyName "Hermes-Meeting-Pipeline-Policy" `
|
|
-Identity "bob@example.com"
|
|
```
|
|
|
|
Propagation can take up to 30 minutes after granting. Verify with:
|
|
|
|
```powershell
|
|
Test-CsApplicationAccessPolicy -Identity "alice@example.com" -AppId "<MSGRAPH_CLIENT_ID>"
|
|
```
|
|
|
|
Without the policy, **any** user's meetings are readable — that's what the permission technically grants. Don't skip this step on a production tenant.
|
|
|
|
## Step 5: Write the Credentials to Your Env File
|
|
|
|
Put the three values you collected into `~/.hermes/.env`:
|
|
|
|
```bash
|
|
MSGRAPH_TENANT_ID=<directory-tenant-id>
|
|
MSGRAPH_CLIENT_ID=<application-client-id>
|
|
MSGRAPH_CLIENT_SECRET=<client-secret-value>
|
|
```
|
|
|
|
Set file permissions so only you can read the secret:
|
|
|
|
```bash
|
|
chmod 600 ~/.hermes/.env
|
|
```
|
|
|
|
## Step 6: Verify the Token Flow
|
|
|
|
Hermes ships a Graph auth smoke-test. From your Hermes install:
|
|
|
|
```python
|
|
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())
|
|
"
|
|
```
|
|
|
|
A successful run prints a long token string and a health dict showing `cached: True` and an `expires_in_seconds` value near 3600. Failures produce a `MicrosoftGraphTokenError` with the Azure error code — the most common are:
|
|
|
|
| Azure error | Meaning | Fix |
|
|
|-------------|---------|-----|
|
|
| `AADSTS7000215: Invalid client secret` | Secret value mismatched or expired. | Generate a new secret in step 2; update `.env`. |
|
|
| `AADSTS700016: Application not found` | Wrong `MSGRAPH_CLIENT_ID` or wrong tenant. | Double-check the values from step 1 are from the same app. |
|
|
| `AADSTS90002: Tenant not found` | Typo in `MSGRAPH_TENANT_ID`. | Copy the Directory (tenant) ID from the app overview again. |
|
|
| `insufficient_claims` at call time (not token time) | Token acquires but Graph returns 401/403. | You skipped step 3 admin-consent, or added permissions but haven't re-consented. Revisit API permissions and click **Grant admin consent** again. |
|
|
|
|
## Rotating the Client Secret
|
|
|
|
Azure client secrets have a hard expiry. Before yours expires:
|
|
|
|
1. Create a second client secret in step 2 without deleting the first one.
|
|
2. Update `MSGRAPH_CLIENT_SECRET` in `~/.hermes/.env` with the new value.
|
|
3. Restart the gateway so the new secret is picked up: `hermes gateway restart`.
|
|
4. Verify with the smoke test above.
|
|
5. Delete the old secret from the Azure portal.
|
|
|
|
## Next Steps
|
|
|
|
Once credentials verify cleanly, continue with:
|
|
|
|
- **Webhook listener setup** — stand up the `msgraph_webhook` gateway platform that receives Graph change notifications.
|
|
- **Pipeline configuration** — configure the Teams meeting pipeline runtime and operator CLI.
|
|
- **Outbound delivery** — wire summaries back into a Teams channel or chat.
|
|
|
|
Those pages land alongside the PRs that add the corresponding runtime. This credentials setup is a standalone prerequisite and is safe to complete in advance.
|