Skip to main content
Findable uses up to four Azure identity surfaces. Each has its own app registration and permission set. Only the Client and Server registrations are required — SharePoint and Azure Search ACL are optional depending on which features you enable.
Tip: The Admin → Health page ([#/admin/about], setting key health.label) shows real-time status for every permission listed below.

1. Client App Registration (clientId)

This is the frontend SPA that users sign into. Configured in the setup wizard (Step 1) and stored as clientId in settings. Azure Portal → App Registrations → Client App
SectionConfiguration
AuthenticationAdd redirect URI: https://your-app-url (or https://localhost:3001 for dev). Enable ID tokens. Set SPA platform.
API PermissionsSee table below
Delegated Permissions (Microsoft Graph):
PermissionTypeRequiredPurpose
User.ReadDelegated✅ YesSign-in and read own profile
Group.Read.AllDelegated✅ YesRead group membership for RBAC
User.Read.AllDelegatedRecommendedPeople picker, user search, directory lookups
Directory.Read.AllDelegatedFallbackAlternative to User.Read.All + Group.Read.All (broader, noisier)
Files.ReadWriteDelegatedOptionalClient-side OneDrive file uploads (drag-and-drop attachment)
Sites.Read.AllDelegatedOptionalSharePoint document library browsing
Sites.SelectedDelegatedOptionalAlternative to Sites.Read.All for restricted site access
Scope acquisition order (client falls back automatically):
  1. User.Read + Group.Read.All + User.Read.All (full)
  2. User.Read + Group.Read.All (groups only — fallback)
  3. User.Read + Directory.Read.All (last resort)
  4. User.Read only (guest users)

2. Server App Registration (graphClientId)

This is the backend server identity used for server-side Graph API calls. Configured in the setup wizard (Step 2) and stored as graphClientId / graphClientSecret in settings. Azure Portal → App Registrations → Server App
SectionConfiguration
Expose an APISet Application ID URI: api://{graphClientId}. Add scope: User.Read (admin consent).
Certificates & SecretsCreate a client secret → store as graphClientSecret.
API PermissionsSee tables below
Application Permissions (Microsoft Graph) — server-to-server, no user context: The server uses these least-privilege application permissions. Grant only what the features you’ve enabled actually need. Required — every authenticated request:
PermissionTypeRequiredPurpose
User.ReadBasic.AllApplication✅ YesResolve the signed-in user’s email/UPN to an Entra id in auth.middleware (getUserIdFromEmail). Only id is selected, so the basic-profile scope is sufficient.
GroupMember.Read.AllApplication✅ YesRead the signed-in user’s transitive group memberships for app-level RBAC (getUserGroups/users/{id}/transitiveMemberOf).
Conditional — only when the named feature is in use:
PermissionTypeRequired whenPurpose
User.Read.AllApplicationFlow Designer Entra tools (entra_get_manager, entra_get_direct_reports, entra_search_users, entra_get_user), the /directory/direct-reports route, the flow assignee resolver for user assignees, or server-side profile syncReads extended user properties (jobTitle, department, officeLocation, employeeId, mobilePhone, businessPhones, companyName) — these are not in the basic profile
Group.Read.AllApplicationFlow Designer assignee resolver resolving group assigneesassigneeresolver.ts::resolveGroup does GET /groups/{id}. GroupMember.Read.All does not authorize reading group properties.
Files.ReadWrite.AllApplicationpersonalFileLocation = OneDriveList/read/upload/create-folder/delete in each user’s OneDrive app folder for the indexer, OneDrive router, and purge job. Files.Read.All is insufficient — the indexer creates folders and the purge job deletes items. See OneDrive Personal Files Setup.
Organization.Read.AllApplicationOptionalLook up tenant display name in settingsservice (GET /organization). Wrapped in try/catch and tagged non-critical; satisfied transitively by User.Read.All or Directory.Read.All.
Broad-fallback (over-privileged, not recommended):
PermissionTypeNotes
Directory.Read.AllApplicationSingle permission that covers all of the above (user reads, group memberships, group properties, organization). Convenient but grants more than the server needs — prefer the least-privilege pair.
Grant admin consent for all application permissions after adding them. The runtime check at Admin → Health passes if Directory.Read.All is present OR one of {User.ReadBasic.All, User.Read.All} AND one of {GroupMember.Read.All, Group.Read.All} are both present.
Delegated Permissions (Microsoft Graph) — OBO flow, user context: These permissions are used by the On-Behalf-Of (OBO) flow when Exchange Online or OneDrive tools execute as the authenticated user. Each must be individually enabled in Admin → Delegated Permissions ([#/admin/delegated], setting key adminNav.delegatedPermissions) after granting consent.
PermissionTypeAdmin SettingPurpose
Mail.ReadDelegatedenableDelegatedGraphMailReadRead user’s email (Exchange)
Mail.SendDelegatedenableDelegatedGraphMailSendSend email as user (Exchange)
Calendars.ReadDelegatedenableDelegatedGraphCalendarReadRead user’s calendar (Exchange)
Calendars.ReadWriteDelegatedenableDelegatedGraphCalendarWriteCreate calendar events as user (Exchange)
MailboxSettings.ReadDelegatedenableDelegatedGraphMailboxSettingsRead out-of-office status (Exchange)
Files.ReadDelegatedenableDelegatedGraphFilesReadRead user’s OneDrive files
Files.ReadWriteDelegatedenableDelegatedGraphFilesReadWriteUpload/create/share OneDrive files
OBO setup steps:
  1. Add the delegated permissions above to the server app (not the client app)
  2. Click “Grant admin consent for [tenant]”
  3. Enable each scope in Admin → Delegated Permissions ([#/admin/delegated])
  4. Ensure graphClientId and graphClientSecret are configured (OBO does not work with managed identity)
Security note: All OBO Graph calls use /me/ endpoints — users can only access their own mailbox, calendar, and OneDrive. Cross-user access is not possible regardless of input parameters. Authentication modes:
ModeEnv/SettingOBO SupportUse Case
Client credentialsgraphClientId + graphClientSecret✅ YesFull functionality including delegated tools
Managed identitygraphAuthType=managedSystemIdentity❌ NoServer-only Graph calls; Exchange/OneDrive tools unavailable

3. SharePoint App Registration (sharePointClientId) — Optional

A separate app registration used for SharePoint document library indexing. Only needed if you use the SharePoint integration. Azure Portal → App Registrations → SharePoint App
SectionConfiguration
Certificates & SecretsCreate a client secret → store as sharePointClientSecret.
API PermissionsSee table below
Application Permissions (Microsoft Graph):
PermissionTypeRequiredPurpose
Sites.Read.AllApplicationOne of theseRead all SharePoint sites and document libraries
Sites.SelectedApplicationOne of theseRead only specific sites (more restrictive, recommended)
If using Sites.Selected, you must grant the app access to each site individually using the SharePoint Entitlement page in Admin or the Grant-PnPAzureADAppSitePermission PowerShell command.
SharePoint Entitlement Administration: The admin UI uses a separate sharePointAdminClientId + API key to grant Sites.Selected permissions to sites. This admin identity needs:
PermissionTypePurpose
Sites.FullControl.AllApplicationGrant site-level permissions to the SharePoint app
Authentication modes:
ModeEnv/SettingUse Case
Client credentialssharePointClientId + sharePointClientSecretStandard setup
Managed identitysharePointAuthType=managedSystemIdentityProduction with MSI

4. Azure Search ACL (Document-Level Security) — Optional

When enabled, Azure AI Search queries pass the user’s identity token so that search results are filtered based on document-level access control lists (ACLs). This is used with SharePoint-indexed content where documents inherit SharePoint permissions. Client App Registration → API Permissions:
PermissionTypeRequiredPurpose
https://search.azure.com/user_impersonationDelegated✅ When ACL enabledPass user identity to Azure Search for permission filtering
Setup steps:
  1. In the client app registration, add API permission: Azure Searchuser_impersonation (Delegated)
  2. Grant admin consent
  3. Enable in Admin → Delegated Permissions ([#/admin/delegated]) → Enable Document-Level ACL
When ACL is enabled, the client acquires an additional token scoped to https://search.azure.com/user_impersonation and sends it alongside search requests.

Quick Reference: Settings ↔ App Registration Mapping

SettingSourceApp Registration
clientIdSetup Wizard Step 1Client (SPA)
tenantIdSetup Wizard Step 1Shared across all
graphClientIdSetup Wizard Step 2Server
graphClientSecretSetup Wizard Step 2Server
graphAuthTypeAdmin → Server Security (Graph) ([#/admin/graphsecurity])Server auth mode
sharePointClientIdAdmin → SharePoint Connection ([#/admin/sharepointconn])SharePoint
sharePointClientSecretAdmin → SharePoint Connection ([#/admin/sharepointconn])SharePoint
sharePointAdminClientIdAdmin → SharePoint Entitlement ([#/admin/sharepointentitlement])SharePoint Admin
enableAzureSearchAclAdmin → Delegated Permissions ([#/admin/delegated])Client + Azure Search

Environment Variable Overrides

The settings above are normally configured through the Setup Wizard or Admin UI and stored in Cosmos DB. However, they can also be set as Azure App Service Application Settings (or environment variables for local development). Environment variables take precedence over Cosmos DB values when present.
TENANT_ID=your-tenant-id
GRAPH_CLIENT_ID=your-server-app-client-id
GRAPH_CLIENT_SECRET=your-server-app-secret
GRAPH_AUTH_TYPE=clientCredentials           # or managedSystemIdentity
SHAREPOINT_CLIENT_ID=your-sp-app-id
SHAREPOINT_CLIENT_SECRET=your-sp-app-secret
Reminder: In production, set these in Azure App Service → Configuration → Application Settings. Do not use a .env file in production deployments.