Authentication — Unique AI Documentation

Authentication

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

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

Option 1: Terraform (Recommended)

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.

module "outlook_semantic_mcp_app" {
  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 Portal → Azure Active Directory → App registrations → New 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 permissions → Add a permission → Microsoft Graph → Delegated permissions:

  3. Go to Certificates & secrets → New 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:

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.

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

Considerations:

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.

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.

Understanding Consent Flows

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

Consent and Permissions

Reference