Exchange Online Admin API (the REST behind EXO V3) cannot be called from the browser — no CORS, and SPFx tokens lack Exchange.Manage
The REST endpoint the Exchange Online PowerShell module V3 uses (https://outlook.office365.com/adminapi/beta/{tenantId}/InvokeCommand) sends no CORS headers for a SharePoint origin, so fetch from an SPFx page fails before authentication. The token SPFx issues for https://outlook.office365.com carries only mail scopes anyway, not Exchange.Manage. Read Exchange configuration with a script the admin runs and an import of its output; for mail flow and mailbox data use Graph.
REST, které používá modul Exchange Online PowerShell V3 (https://outlook.office365.com/adminapi/beta/{tenantId}/InvokeCommand), neposílá pro původ SharePointu hlavičky CORS, takže fetch ze stránky SPFx selže ještě před ověřením. Token, který SPFx pro https://outlook.office365.com vydá, nese stejně jen poštovní obory, ne Exchange.Manage. Konfiguraci Exchange čti skriptem, který spustí správce, a importem výstupu; tok pošty a data schránek ber z Graphu.
Symptom
From an SPFx web part you try to list mailboxes, forwarding or mailbox permissions without an app-only registration. Every request to adminapi ends with TypeError: Failed to fetch, no HTTP status, no readable body.
Cause
Measured from a modern SharePoint page as a global admin (November 2026):
aadTokenProviderFactory.getTokenProvider().getToken('https://outlook.office365.com')succeeds, but thescpclaim lists onlyMail.*,Calendars.*,User.*,Group.*,People.*,Files.*,Tasks.*— noExchange.Manage.fetchtoadminapi/beta/{tenantId}/InvokeCommandand to…/Mailboxfails withFailed to fetcheven with a made-up token, so the browser blocks it before the server looks at authentication.- A
securitypolicyviolationlistener caught nothing, so it is not the page's Content Security Policy. Amode: 'no-cors'request goes out (opaque response). - Control:
https://outlook.office.com/api/v2.0/mewith a made-up token returns a readable401— the mail API allows CORS, the admin API does not.
Fix
- Exchange configuration (forwarding, Full Access / Send As, inbox rules, remote domains): generate a PowerShell script (
Get-Mailbox,Get-MailboxPermission,Get-InboxRule,Get-RemoteDomain), let the admin run it, and import the output into your app. - Message trace: Graph
GET /admin/exchange/tracing/messageTraceswith delegatedExchangeMessageTrace.Read.All(last 90 days, 100 requests per 5 minutes per tenant). It needs a one-time service principal for Microsoft's app8bd644d1-64a1-4d4b-ae52-2e0cbf64e373in the tenant; without it the call returns 403 "Service principal-less authentication failed". - Mailbox size, activity and type: beta
reports/getMailboxUsageDetail(period='D7')?$format=application/jsonreturnsrecipientType(User,Shared),hasArchive, quotas and storage — see usage reports in the browser.
How to tell CORS from CSP: call the endpoint with a fake token while a securitypolicyviolation listener is attached. A CSP block fires the event; a CORS block does not, and the same URL succeeds with mode: 'no-cors'.
Sources
- List messageTraces (permissions, throttling): https://learn.microsoft.com/graph/api/messagetracingroot-list-messagetraces?view=graph-rest-1.0
- Graph-based message trace API onboarding (service principal): https://learn.microsoft.com/exchange/monitoring/trace-an-email-message/graph-api-message-trace
- Live measurement, November 2026 (as described above).