Microsoft 365 integration (Teams + Outlook + Entra ID + SharePoint)

ActivityLog ingests Microsoft 365 activity through a single Azure Function App named ActivityLog-O365, which pulls from the Office 365 Management Activity API and Microsoft Graph CallRecords and routes events to ActivityLog systems by workload.

Workload ActivityLog system Source
Teams (channel messages, calls, meetings) teams (or whatever you name it) O365 Mgmt API Audit.General + Graph CallRecords
Outlook / Exchange (email, calendar) outlook O365 Mgmt API Audit.Exchange
Entra ID (sign-ins, directory audit) entra O365 Mgmt API Audit.AzureActiveDirectory
SharePoint + OneDrive (file activity) sharepoint O365 Mgmt API Audit.SharePoint

One Function App, four token routes. This is the architecture today — earlier drafts of the integration specs had separate Function Apps per workload; that's been consolidated.

Where the canonical deployment docs live

This guide is the user-facing overview. The actual deploy steps — Azure resource provisioning, Entra app reg, Key Vault secrets, app settings — are maintained in the ActivityLog-Integrations repo as operator runbooks. Use these as your source of truth:

Doc What it covers
../../../ActivityLog-Integrations/Teams/DEPLOY.md The canonical deploy spec. Hosting layout, app permissions, KV secrets, app settings, deploy pipeline, adding new content types.
../../../ActivityLog-Integrations/Azure/Teams-FunctionApp-Handoff.md Historical provisioning record (Teams-only era). Useful when standing up the stack in a new Azure tenant.
../../../ActivityLog-Integrations/Azure/Outlook-FunctionApp-Handoff.md Historical Outlook-only handoff. Now superseded by the consolidated Function App.
../../../ActivityLog-Integrations/Common-Architecture.md Auth contract, storage modes, retention defaults, idempotency schema across all integrations.

Workload-specific message catalogues:

Doc What it covers
../../../ActivityLog-Integrations/Teams/SPEC.md Teams message types, mapping rules, attribute schema
../../../ActivityLog-Integrations/Outlook/SPEC.md Email + calendar event mapping
../../../ActivityLog-Integrations/EntraID/SPEC.md Sign-in + directory-audit mapping
../../../ActivityLog-Integrations/SharePoint/SPEC.md File-activity event mapping

The summary below describes what you'll see in the ActivityLog portal once the Function App is running — read it first, then go to the deploy doc for the actual stand-up.

High-level architecture

┌──────────────────────────────────────────────┐
│  Microsoft 365 tenant (your org)             │
│   ├── Teams                                  │
│   ├── Exchange / Outlook                     │
│   ├── Entra ID                               │
│   └── SharePoint / OneDrive                  │
└────────────────────┬─────────────────────────┘
                     │ O365 Mgmt Activity API
                     │ (`Audit.General`, `Audit.Exchange`,
                     │  `Audit.AzureActiveDirectory`, `Audit.SharePoint`)
                     ▼
       ┌──────────────────────────────┐
       │  ActivityLog-O365            │
       │  (Azure Function App, Y1)    │
       │   - System-assigned MI       │
       │   - One Entra app reg        │
       │   - Three Graph permissions  │
       │     + one O365 Mgmt perm     │
       └──────┬────────────┬──────────┘
              │            │
              │            │ Microsoft Graph
              │            │ (CallRecords.Read.All)
              │            ▼
              │     Teams call detail
              ▼
       Route by `Workload` field
       ├── MicrosoftTeams ──▶  POST /messages  (teams token)
       ├── Exchange      ──▶  POST /messages  (outlook token)
       ├── AzureActiveDirectory ──▶  POST /messages  (entra token)
       └── SharePoint    ──▶  POST /messages  (sharepoint token)
                  │
                  ▼
            ActivityLog API

One client credential authenticates against two resources: the O365 Mgmt API (for audit content) and Graph (for call records). The Function App routes each event to the right ActivityLog system based on the audit event's Workload field.

What you need to set up

You provision four things in ActivityLog before the Function App can start ingesting:

  1. Four systems, one per workload, with whatever names you prefer (e.g. teams, outlook, entra, sharepoint).
  2. One token per system — five-year retention recommended (compliance-shaped events). See 20-setup-system-tokens.md.
  3. One Entra app registration in your M365 tenant, with the three Graph permissions + one O365 Mgmt API permission listed below.
  4. One Function App (ActivityLog-O365) wired up per the canonical deploy doc.

The Fyin-managed staging tenant has a pre-built version of this Function App that ingests Fyin's own M365 activity. If you're a customer evaluating, the easiest path is to mirror that setup in your own Azure subscription using the deploy doc as the template.

Required Entra app registration permissions

In your M365 tenant, create an Entra app registration with application permissions (not delegated):

Permission Resource Why
ActivityFeed.Read Office 365 Management APIs Subscribe + pull from all four audit content types
CallRecords.Read.All Microsoft Graph Teams call detail (per-participant session start/end) — not in the audit feed
User.Read.All Microsoft Graph Resolve user IDs ↔ UPN/displayName for actor mapping

Tenant admin consent is required for all three. Once consented, the same client credential works against both resources (the access token is requested per-resource at runtime).

Earlier provisioning runs granted ChannelMessage.Read.All, Chat.Read.All, OnlineMeetingArtifact.Read.All, Reports.Read.All, Files.Read.All. These are redundant under the Mgmt API model and have been removed. If you're following an older handoff doc that lists them, ignore those entries — see ../../../ActivityLog-Integrations/Azure/Teams-FunctionApp-Handoff.md for the historical note.

Workload coverage

Teams (Workload = MicrosoftTeams)

Routed to the teams token. Storage mode: lean metadata (the O365 audit feed scrubs body content, so we have nothing to ingest as body).

Event types you'll see:

Type Meaning
teams.message.created A channel or chat message was posted (metadata only)
teams.meeting.created / .joined / .left / .ended Meeting lifecycle
teams.call.started / .ended Call lifecycle (from CallRecords, joined to audit)
teams.user.added / .removed Team/channel membership changes

Full catalogue: ../../../ActivityLog-Integrations/Teams/SPEC.md.

Outlook (Workload = Exchange)

Routed to the outlook token. Storage mode: lean metadata (body content scrubbed by audit).

Event types:

Type Meaning
outlook.email.sent / .received Send and receive (with subject line in metadata, never body)
outlook.calendar.event.created / .updated / .cancelled Calendar lifecycle
outlook.meeting.accepted / .declined Meeting RSVP

Full catalogue: ../../../ActivityLog-Integrations/Outlook/SPEC.md.

Entra ID (Workload = AzureActiveDirectory)

Routed to the entra token. Storage mode: lean metadata. Two downstream streams:

Stream Content
signins Interactive user sign-ins, success and failure
directory Directory-audit events: user added, group changed, role assigned

Event types:

Type Meaning
entra.signin.success / .failure Sign-in attempts (IP, app, MFA result in metadata)
entra.user.added / .deleted / .modified User lifecycle
entra.role.assigned / .removed Role changes
entra.group.member.added / .removed Group membership

Full catalogue: ../../../ActivityLog-Integrations/EntraID/SPEC.md.

SharePoint + OneDrive (Workload = SharePoint or OneDrive)

Routed to the sharepoint token. Storage mode: lean metadata (file names + paths in metadata, never file content).

Event types (whitelist — others are dropped by default):

Type Meaning
sharepoint.file.viewed / onedrive.file.viewed File opened
sharepoint.file.edited / onedrive.file.edited File edited
sharepoint.file.uploaded / onedrive.file.uploaded File added
sharepoint.file.downloaded / onedrive.file.downloaded File retrieved
sharepoint.file.deleted / onedrive.file.deleted File removed
sharepoint.file.shared / onedrive.file.shared File shared

Weak-signal operations (FolderCreated, FileMoved, FileCopied, PageViewed, SearchQueryPerformed) are blocked by default to keep volume reasonable.

Full catalogue: ../../../ActivityLog-Integrations/SharePoint/SPEC.md.

Operational characteristics

Concern Behavior
Latency 30–90 minutes — this is the O365 Mgmt API's publication lag, not anything ActivityLog adds. The Mgmt API publishes audit events in batches on a schedule.
Idempotency Each event has an audit Id from Microsoft. The Function App uses it as sourceEventId — retries collapse safely.
Backfill on first run On first start, the Function App pulls the last 7 days from the Mgmt API. Older history requires a separate REST-API backfill (not built in).
Watermark Persisted in Azure Table Storage (activitylogfunctions storage account, o365_watermark partition). If the Function App restarts, it resumes where it left off.
Per-workload disable App-setting toggle per workload. If you don't have a SharePoint use case, leave it off and save the pull.

Retention recommendation

All four M365 workloads ship with 1825-day (5-year) retention on their tokens by default. This is the typical security-audit window and matches the Common Architecture default for activity-event class sources. Override per token if your compliance posture differs.

Cost (Azure side)

Resource Tier Estimated monthly cost
Function App (Linux Consumption / Y1) Y1 $0 base, $0 from executions (well under the 1M/month free grant)
Storage account (shared across ActivityLog Function Apps) Standard LRS $1–3
Entra app registration n/a $0
Key Vault ops Standard <$0.01
Total **$1–3 per month**

Application Insights is deliberately not provisioned on the Function App — the operational ceiling vs the value at this workload is poor. App-Insights-less debugging is via the deploy doc's logging guidance.

Status today

Workload Status
Teams Live on Fyin's internal tenant; ready to provision for customers
Outlook Ready to implement — same Function App; one more content-type subscription + one new token
Entra ID Ready to implement — same as Outlook
SharePoint Ready to implement — same as Outlook

The Teams workload is the proven path; the other three plug into the same Function App via the "Adding a new O365 content type" playbook in the deploy spec.

What's next

Goal Doc
Stand up the Function App ../../../ActivityLog-Integrations/Teams/DEPLOY.md
Provision the deploy pipeline ../../../ActivityLog-Integrations/Azure/Pipeline-Setup.md
Understand event schema and idempotency ../../../ActivityLog-Integrations/Common-Architecture.md
Mint the four tokens 20-setup-system-tokens.md
Query the events back 60-query-api.md