Outlook Semantic MCP - Authentication

7 min read

Outlook Semantic MCP - Authentication

Overview

The Outlook Semantic MCP Server requires a Microsoft Entra ID (formerly Azure AD) app registration with delegated permissions to access Microsoft Graph API on behalf of users.

How the app registration is provisioned depends on your deployment model:

  • Unique SaaS — Unique provisions and manages the registration; you grant admin consent

  • Self-Hosted — your organization provisions the registration, manages secrets, and operates the server

For technical details about the OAuth flow, see Authentication Flows and FAQ - Why do I need a client ID and client secret?.

Required Permissions

All permissions are delegated — they act on behalf of the signed-in user. None require admin consent. Mail.ReadWrite.Shared is always requested at OAuth time (even when DELEGATED_ACCESS_SCAN=disabled).

Permission

Type

Admin Consent

User.Read

Delegated

No

Mail.ReadWrite

Delegated

No

Mail.ReadWrite.Shared

Delegated

No

MailboxSettings.Read

Delegated

No

People.Read

Delegated

No

offline_access

Delegated

No

For full justifications, see Microsoft Graph Permissions.

Unique SaaS

Recommended for most clients. When Unique runs Outlook Semantic MCP, Unique provisions the Entra ID app registration for you. You only need to grant admin consent:

none
https://login.microsoftonline.com/organizations/adminconsent?client_id=ba326974-edcf-49ef-bf7a-74b3e0ea450a

The consent prompt lists the Required Permissions above. None require admin consent — users can also approve permissions themselves on first connection. Granting admin consent up front is optional but skips the per-user consent prompt.

If your organization uses multiple Azure tenants, confirm you are granting consent for the correct directory. See Grant tenant-wide admin consent to an application for a tenant-specific admin consent URL; use application (client) ID .

Self-Hosted

When your organization hosts Outlook Semantic MCP, your team manages the full setup: Entra app registration, redirect URIs, secret rotation, and server configuration.

App Registration

Prerequisite: Assumes an existing Azure Key Vault resource (referenced as azurerm_key_vault.main below). The Terraform module writes the client secret to Key Vault automatically.

none
module "outlook_semantic_mcp_app" {
  # Adjust path based on your working directory — see note below
  source = "<path-to-connectors-repo>/services/outlook-semantic-mcp/deploy/terraform/azure/outlook-semantic-mcp-entra-application"

  display_name     = "Outlook Semantic MCP Server"
  sign_in_audience = "AzureADMyOrg"  # Single tenant
  notes            = "MCP server for Outlook email access"

  redirect_uris = [
    "https://outlook.semantic.mcp.example.com/auth/callback"
  ]

  confidential_clients = {
    production = {
      client_secret = {
        key_vault_id     = azurerm_key_vault.main.id
        end_date         = "2027-01-01T00:00:00Z"
        rotation_counter = 1
      }
    }
  }
}

Note: Run Terraform from the services/outlook-semantic-mcp/ directory, or adjust the source path to the full path from your repository root (e.g., ./services/outlook-semantic-mcp/deploy/terraform/azure/outlook-semantic-mcp-entra-application).

service_principal_configuration (optional): When set, the module creates a service principal and pre-grants delegated permissions tenant-wide via azuread_service_principal_delegated_permission_grant. Omit this variable for multi-tenant deployments where admin consent is granted by each customer tenant individually.

Option 2: Azure Portal (Manual)

  1. Go to Azure PortalAzure Active DirectoryApp registrationsNew registration: - Name: Outlook Semantic MCP Server - Supported account types: Accounts in this organizational directory only - Redirect URI: Web — https://outlook.semantic.mcp.example.com/auth/callback

  2. Go to API permissionsAdd a permissionMicrosoft GraphDelegated permissions: - Add all permissions listed under Required Permissions

  3. Go to Certificates & secretsNew client secret: - Set description and expiration - Copy the secret value immediately (shown only once)

  4. Go to Overview and note the Application (client) ID and Directory (tenant) ID

Redirect URI Configuration

The redirect URI must match exactly what's configured in the app registration:

none
https://<your-domain>/auth/callback

Examples:

  • Production: https://outlook.semantic.mcp.example.com/auth/callback

  • Local development: http://localhost:9542/auth/callback

Multiple redirect URIs can be configured for different environments. If you run multiple server instances (e.g. staging and production), add each instance's redirect URI to the same app registration — you do not need a separate app registration per instance.

The redirect URI is derived from SELF_URL: the app registration redirect URI must be <SELF_URL>/auth/callback. This is unrelated to the MICROSOFT_PUBLIC_WEBHOOK_URL variable, which controls webhook callbacks only.

Tenant Configuration

The Entra ID app registration's sign-in audience controls which users can authenticate. The service works identically in both modes — there is no code-level difference, no MICROSOFT_TENANT_ID environment variable, and no runtime tenant configuration. The choice is made once at app registration time.

Question

→ Pick

Will only users from your own Microsoft 365 organization connect?

Single Tenant

Will users from multiple organizations (e.g. customer tenants) connect to the same deployment?

Multi-Tenant

Single Tenant

Setting

Value

Azure Portal → "Supported account types"

Accounts in this organizational directory only

Terraform sign_in_audience

"AzureADMyOrg"

Only users from the tenant where the app is registered can sign in. Admin consent is optional: set the service_principal_configuration Terraform variable to pre-grant permissions tenant-wide and skip per-user prompts.

Multi-Tenant

Setting

Value

Azure Portal → "Supported account types"

Accounts in any organizational directory

Terraform sign_in_audience

"AzureADMultipleOrgs" (Terraform default)

Users from any Microsoft 365 organization can sign in. When a user authenticates, Microsoft's OAuth flow automatically routes them to their home tenant.

Customer onboarding:

  1. Create a single app registration in your own tenant with one MICROSOFT_CLIENT_ID and MICROSOFT_CLIENT_SECRET.

  2. Each customer tenant admin grants consent for their organization:

    none
    https://login.microsoftonline.com/{customer-tenant-id}/adminconsent?client_id={your-client-id}

    When approved, Microsoft creates an Enterprise Application in their tenant and grants the delegated permissions tenant-wide.

  3. After consent, users from that tenant can sign in and connect their mailbox.

Considerations:

  • No service_principal_configuration: Set to null for multi-tenant — service principals are created per-customer-tenant via the admin consent URL, not Terraform.

  • Data isolation: All tenants share the same database. Data is scoped per-user; there is no tenant-level isolation boundary within the service.

  • Enterprise Application management: Each customer tenant admin can independently control user assignment and revoke access from their Azure Portal.

  • Compliance: Some organizations require dedicated infrastructure for data residency — deploy a separate instance per tenant with single-tenant configuration in that case.

Secret Management

The service requires four secrets for authentication and data protection. All must be stored in Kubernetes Secrets (not ConfigMaps).

Variable

Format

Generation

Purpose

MICROSOFT_CLIENT_SECRET

Azure-generated string

Created in Entra ID app registration

Authenticates the server to Microsoft Entra ID during OAuth flows

MICROSOFT_WEBHOOK_SECRET

128-char hex string

openssl rand -hex 64

Validates that incoming webhook notifications come from Microsoft Graph

AUTH_HMAC_SECRET

64-char hex string

openssl rand -hex 32

Signs OAuth session state during the MCP client authentication flow (HMAC-SHA256)

ENCRYPTION_KEY

64-char hex string

openssl rand -hex 32

Encrypts Microsoft OAuth tokens (access + refresh) at rest in PostgreSQL using AES-256-GCM

MICROSOFT_CLIENT_SECRET

What happens if it expires or is deleted: All OAuth flows fail immediately — no new users can connect, and existing users' tokens cannot be refreshed. Once an access token expires (~1 hour), that user's sync and tool calls stop working.

How to rotate:

  1. Create a new client secret in the Entra ID app registration (keep the old one active during transition)

  2. Update the Kubernetes secret with the new value

  3. Restart pods to pick up the new secret

  4. Verify authentication works (connect a test user)

  5. Delete the old secret from Entra ID

Zero-downtime rotation is supported because Microsoft allows multiple active client secrets simultaneously.

Best practices: Set an appropriate expiration; rotate before expiration; store in Key Vault (the Terraform module does this automatically); set up Azure alerts for upcoming expiration.

MICROSOFT_WEBHOOK_SECRET

Passed to Microsoft as the clientState field when creating Graph subscriptions. Microsoft returns it unchanged in every webhook payload — the server rejects any notification where the value does not match.

What happens if it is changed: All existing subscriptions break.

  • Live catch-up stops — all incoming email notifications are rejected until subscriptions are recreated.

  • Full sync is unaffected — it pulls directly from Microsoft Graph and does not use webhooks.

  • Emails received during the gap are not ingested until subscriptions are recreated. Once a user calls reconnect_inbox, live catch-up picks them up from the last watermark.

How to rotate:

  1. Generate a new secret: openssl rand -hex 64

  2. Update the Kubernetes secret and redeploy the service

  3. All users must call reconnect_inbox to recreate their subscriptions with the new secret

Plan this as a maintenance window — there is no zero-downtime rotation path.

ENCRYPTION_KEY

Encrypts Microsoft OAuth tokens at rest in PostgreSQL using AES-256-GCM. Tokens are decrypted in memory when the server needs to call Microsoft Graph.

What happens if it is changed: All stored tokens become unreadable. Every user's sync stops and all tool calls fail. Users must re-authenticate by calling reconnect_inbox.

How to rotate:

  1. Generate a new key: openssl rand -hex 32

  2. Update the Kubernetes secret and redeploy

  3. All users must call reconnect_inbox to re-authenticate

Plan this as a maintenance window — there is no zero-downtime rotation path.

AUTH_HMAC_SECRET

Signs and validates OAuth session state during the MCP client authentication flow (HMAC-SHA256), preventing CSRF and session tampering during the OAuth redirect sequence.

What happens if it is changed: Only in-flight OAuth sessions are invalidated. Already-connected users are not affected — their existing tokens and subscriptions continue to work.

How to rotate:

  1. Generate a new secret: openssl rand -hex 32

  2. Update the Kubernetes secret and redeploy

  3. Users mid-OAuth-flow will see an error and need to restart the flow; already-authenticated users are unaffected

This is the lowest-impact secret to rotate.

For the full security context, see Secret Management.

This is standard Microsoft behavior, not Outlook Semantic MCP specific. All Microsoft 365 apps use the same consent model.

Because no permission in this app requires admin consent, users can complete the full consent flow independently:

  1. User consent — on first connection, the user sees the Microsoft consent screen and approves the listed permissions

  2. Optional admin pre-consent — an admin can grant consent organisation-wide via Azure Portal to skip the per-user consent prompt

User Reconnection Experience (The "Login Flicker"):

After first connection, subsequent reconnections show a quick "flicker" (brief redirect sequence). This is normal — Microsoft validates the existing session through rapid OAuth redirects. See FAQ - Login "Flicker" for details.

For detailed explanation, see Microsoft Graph Permissions - Understanding Consent Requirements.

Microsoft Documentation

App Registration

Reference

Last updated