Delegated access and security
GriMoire combines SharePoint's delegated browser-side model with a backend proxy that separates model access, MCP session execution, and user data persistence into distinct security layers.
The four-part auth story
1. Delegated Microsoft 365 access in the browser
For Microsoft Graph calls — including Copilot endpoints like /beta/copilot/search and /beta/copilot/retrieval — GriMoire uses the built-in SPFx AadHttpClient.
Why that matters:
- the calls run in the current user's delegated context
- the solution fits naturally into SharePoint's hosting and consent model
- the frontend does not need its own custom browser-side Entra app registration for those APIs
All 19 permissions declared in the SPFx manifest are delegated scopes. The deployment dialog shows a "full trust client-side code" warning — this is standard for SPFx solutions with webApiPermissionRequests and does not mean the solution has application-level access. Every Microsoft 365 call runs as the signed-in user and is limited to what that user can already access.
2. API-key-authenticated backend proxy
The web part sends requests to the backend with a Proxy API Key for routes that handle model access, speech synthesis, and MCP session management.
That key does not replace delegated Microsoft 365 auth. It protects the backend proxy so the browser can call backend endpoints intentionally and the backend can distinguish valid clients from noise.
API-key-protected routes include:
- chat completion routing
- realtime token issuance
- speech synthesis
- MCP session connect and execute
3. Easy Auth for user data routes
User-specific persistence routes — notes and preferences — are protected by Azure Easy Auth instead of the API key. The deploy script automatically creates an Entra app registration ("Grimoire Backend API") and configures Easy Auth on the Function App.
The SPFx web part acquires a delegated token for this backend API using AadHttpClient and sends it with requests to /api/user/notes and /api/user/preferences. The backend middleware extracts the authenticated user identity from Azure Easy Auth headers — the frontend never sends a user ID in the request body.
Why that matters:
- user data is protected by Azure AD authentication, not just an API key
- the backend knows exactly which user is making the request
- the deploy script handles the Entra app registration and Easy Auth configuration automatically
4. Managed identity for model access
In Azure deployment mode, the backend uses managed identity for Azure model access via DefaultAzureCredential with token caching, instead of storing long-lived model credentials in the frontend.
Why that matters:
- model access is kept server-side
- the browser never needs direct model credentials
- Azure role assignment and backend identity become the control surface
Where tenant approval still matters
This model reduces friction, but it does not remove governance.
You still need:
- SharePoint app catalog deployment
- API access approval for the scopes declared by the SPFx solution package (Graph, Backend API, and Agent 365)
- Agent 365-related approval and tenant readiness
- the one-time Agent 365 service principal setup step
So the right way to describe the security story is:
minimal custom browser auth friction, but still strong tenant governance.
Security boundaries to keep in mind
- Microsoft Graph calls (including Copilot endpoints) are user-context delegated calls.
- Model calls are backend-routed and should stay backend-routed.
- MCP traffic should go through the backend, not direct from the browser.
- User data routes are Easy Auth-protected — the backend verifies the caller's identity.
- SharePoint approval and Agent 365 approval remain tenant-controlled gates.
Your responsibility
GriMoire uses delegated access only — every Microsoft 365 call runs in the current user's context, and the backend uses managed identity for model access. No application-level secrets are stored in the browser.
That said, the Azure Functions backend is publicly reachable by default. Most routes are protected by an API key. User data routes (/api/user/*) add Easy Auth on top of that. Depending on your organization's security posture, you may want to apply additional Azure-level protections such as:
- VNet integration or private endpoints for the Function App
- Azure API Management in front of the backend
- IP restrictions or Azure Front Door
- Network security groups limiting inbound traffic
These are standard Azure networking configurations and are outside the scope of this solution. The authors provide GriMoire as-is and accept no responsibility for the security of your deployment. You are responsible for hardening the backend to meet your organization's requirements.