Register a Microsoft Graph Application

The Teams meeting pipeline reads meeting transcripts, recordings, and related artifacts from Microsoft Graph usingapp-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 needtenant admin rights(or an admin to grant consent on your behalf) to finish this. Bookmark the values you collect — they go into~/.hermes/.envat the end.

~/.hermes/.env

Prerequisites​

Step 1: Create the App Registration​

  1. Sign in toentra.microsoft.comas a tenant admin.
  2. Navigate toIdentity → Applications → App registrations.
  3. ClickNew 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. ClickRegister.

Hermes Teams Meeting Pipeline

You’ll land on the app’s overview page. Copy two values:

MSGRAPH_CLIENT_ID MSGRAPH_TENANT_ID

Step 2: Create a Client Secret​

  1. In the left nav, openCertificates & secrets.
  2. ClickNew client secret.
  3. Description:hermes-graph-secret.Expires:pick a value that matches your rotation policy (6-24 months is typical).
  4. ClickAdd.
  5. Copy theValuecolumn immediately — it’s only shown once. That value isMSGRAPH_CLIENT_SECRET.

hermes-graph-secret MSGRAPH_CLIENT_SECRET

TheSecret IDcolumn is not the secret. You want theValuecolumn.

TheSecret IDcolumn is not the secret. You want theValuecolumn.

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, openAPI permissions.
  2. ClickAdd 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, clickGrant admin consent for. The Status column should flip to a green checkmark for every permission.

<your tenant>

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.

OnlineMeetings.Read.All OnlineMeetingTranscript.Read.All

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.

OnlineMeetingRecording.Read.All CallRecords.Read.All

Required for outbound summary delivery (Graph mode only)​

Ifplatforms.teams.extra.delivery_modeisgraph, the pipeline posts summaries into a Teams channel or chat via the Graph API. Skip these if you useincoming_webhookdelivery mode instead.

platforms.teams.extra.delivery_mode graph incoming_webhook | 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 setchat_idas the delivery target). |

ChannelMessage.Send Chat.ReadWrite.All chat_id

OnlineMeetings.ReadWrite.All Chat.ReadWrite .All

By default, application permissions likeOnlineMeetings.Read.Allgrant the app access toeverymeeting 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.

OnlineMeetings.Read.All

Microsoft providesApplication Access Policiesfor 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):

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"

Propagation can take up to 30 minutes after granting. Verify with:

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

Without the policy,anyuser’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:

~/.hermes/.env

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:

chmod 600 ~/.hermes/.env

Step 6: Verify the Token Flow​

Hermes ships a Graph auth smoke-test. From your Hermes install:

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())"

A successful run prints a long token string and a health dict showingcached: Trueand anexpires_in_secondsvalue near 3600. Failures produce aMicrosoftGraphTokenErrorwith the Azure error code — the most common are:

cached: True expires_in_seconds MicrosoftGraphTokenError | 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 | WrongMSGRAPH_CLIENT_IDor wrong tenant. | Double-check the values from step 1 are from the same app. | | AADSTS90002: Tenant not found | Typo inMSGRAPH_TENANT_ID. | Copy the Directory (tenant) ID from the app overview again. | | insufficient_claimsat 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 clickGrant admin consentagain. |

AADSTS7000215: Invalid client secret .env AADSTS700016: Application not found MSGRAPH_CLIENT_ID AADSTS90002: Tenant not found MSGRAPH_TENANT_ID insufficient_claims

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. UpdateMSGRAPH_CLIENT_SECRETin~/.hermes/.envwith 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.

MSGRAPH_CLIENT_SECRET ~/.hermes/.env hermes gateway restart

Next Steps​

Once credentials verify cleanly, continue with:

msgraph_webhook

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.