Skip to main content

SPEC 017 — Microsoft Integration

FieldValue
StatusDRAFT
PriorityP2 — Integration
Backendequa-server/modules/microsoft/
Frontendequa-web/src/shared/helpers/ms/msGraph.ts

1. Feature Purpose

The Microsoft Integration connects Equa organizations to Microsoft 365 via Azure AD. It uses the OAuth 2.0 client credentials flow to obtain application-level access to the Microsoft Graph API, enabling the platform to manage Microsoft 365 groups on behalf of organizations. This powers team provisioning, group membership synchronization, and future SharePoint/Teams integrations without requiring individual user consent.

2. Current State (Verified)

2.1 OAuth Client Credentials Flow

DetailValue
Grant typeclient_credentials (application-level, no user interaction)
Authorityhttps://login.microsoftonline.com/{MS_AUTH_TENANT_ID}
Scopehttps://graph.microsoft.com/.default
Library@azure/msal-node ConfidentialClientApplication
Env varsMS_AUTH_CLIENT_ID, MS_AUTH_TENANT_ID, MS_AUTH_SECRET, MS_AUTH_ENABLED

2.2 Graph API Helper

DetailValue
Fileequa-web/src/shared/helpers/ms/msGraph.ts
Client@microsoft/microsoft-graph-client via Client.init()
Auth providerPasses access token from MSAL into the Graph client auth callback

2.3 Microsoft Group Binding

DetailValue
StorageOrganizations.microsoftGroup (uuid field on existing Organizations entity)
LifecycleGroup ID stored when an organization links to an existing M365 group or creates a new one
UsageUsed to resolve group members, sync membership, and manage group settings via Graph API

2.4 Backend Module

ComponentPath
Module rootequa-server/modules/microsoft/
Endpointsequa-server/modules/api/src/endpoints/microsoft-endpoints.ts

3. Data Model

The Microsoft integration does not introduce dedicated entities. It relies on a single field on the existing Organizations table and the Azure AD tenant for all state.

Organizations (relevant field)

ColumnTypeConstraints
microsoftGroupuuidnullable — Azure AD group object ID

Token Caching

MSAL’s ConfidentialClientApplication handles in-memory token caching and automatic refresh. No database persistence is required for tokens since the client credentials flow can always obtain a new token from Azure AD without user interaction.

4. API Endpoints

MethodPathAuthDescription
GET/api/v1/organizations/:id/microsoft/statusYesCheck if MS integration is enabled and group is linked
POST/api/v1/organizations/:id/microsoft/link-groupYesAssociate an existing M365 group with the organization
POST/api/v1/organizations/:id/microsoft/create-groupYesCreate a new M365 group and link it
DELETE/api/v1/organizations/:id/microsoft/unlink-groupYesRemove the M365 group association
GET/api/v1/organizations/:id/microsoft/groupYesFetch linked group details from Graph API
GET/api/v1/organizations/:id/microsoft/group/membersYesList members of the linked M365 group
POST/api/v1/organizations/:id/microsoft/group/membersYesAdd a member to the linked M365 group
DELETE/api/v1/organizations/:id/microsoft/group/members/:memberIdYesRemove a member from the linked M365 group
POST/api/v1/organizations/:id/microsoft/sync-membersYesSync Equa team members to/from M365 group membership

5. Frontend Components

ComponentPathDescription
msGraph helperequa-web/src/shared/helpers/ms/msGraph.tsInitializes Microsoft Graph client with token auth provider
Settings integration sectionequa-web/src/modules/settings/Organization settings page includes Microsoft group linking UI

Frontend Behavior

  • Feature gate — Microsoft integration UI elements are hidden when MS_AUTH_ENABLED is false.
  • No user OAuth — Since the integration uses client credentials, there is no user-facing OAuth popup. Admins link groups by entering or selecting a group ID.
  • Graph client — The frontend helper (msGraph.ts) creates a Graph client instance; however, in practice most Graph API calls are proxied through the backend to avoid exposing the application secret.
  • Group status display — Shows linked group name, member count, and last sync time when a group is associated.

6. Business Rules

  1. Application-level auth — The client credentials flow grants tenant-wide access; no individual user consent is required. This requires Azure AD admin consent for the app registration.
  2. One group per organization — Each Equa organization links to at most one M365 group via Organizations.microsoftGroup.
  3. Feature flag gating — All Microsoft endpoints return 404 when MS_AUTH_ENABLED is false, preventing accidental exposure.
  4. Token lifecycle — MSAL handles token acquisition, caching, and refresh internally. Tokens are never persisted to disk or database.
  5. Tenant scoping — The integration operates within a single Azure AD tenant defined by MS_AUTH_TENANT_ID. Multi-tenant support is not implemented.
  6. Group creation defaults — Newly created M365 groups are configured as private with mail-enabled security group type.
  7. Member sync direction — Sync is bidirectional: Equa team members are added to the M365 group, and M365 group members without Equa accounts are flagged for invitation.
  8. Unlink preserves group — Unlinking an M365 group from an Equa organization clears microsoftGroup but does not delete the group in Azure AD.
  9. Admin-only operations — Group linking, unlinking, creation, and member management require organization admin role.
  10. Graph API error handling — 401/403 from Graph API triggers a token refresh and single retry; persistent failures are surfaced to the user.

7. Acceptance Criteria

  • Admin can link an existing M365 group to the organization by group ID
  • Admin can create a new M365 group from the Equa settings page
  • Admin can unlink the M365 group; the Azure AD group is not deleted
  • Linked group details (name, description, member count) display correctly
  • Group members list shows current M365 group membership
  • Admin can add a member to the M365 group via the Equa UI
  • Admin can remove a member from the M365 group via the Equa UI
  • Member sync reconciles Equa team members with M365 group membership
  • All Microsoft endpoints return 404 when MS_AUTH_ENABLED is false
  • Token refresh is automatic and transparent to the user
  • Non-admin users cannot access Microsoft integration endpoints
  • Graph API errors are surfaced with actionable messages

8. Risks

RiskImpactMitigation
Tenant-wide application permissionsOver-privileged access to all tenant resourcesRequest minimum Graph API permissions (Group.ReadWrite.All only); audit app registration scopes
MS_AUTH_SECRET exposureFull tenant access compromiseStore in vault; rotate on schedule; never log or return in API responses
Single-tenant limitationCannot support organizations in different Azure AD tenantsDocument limitation; plan multi-tenant app registration if demand arises
Azure AD admin consent requiredOnboarding friction for new tenantsProvide clear setup documentation; consider admin consent URL generator
In-memory token cache lost on restartMinor latency spike on first post-restart callAcceptable trade-off; MSAL re-acquires tokens automatically
Graph API rate limits (10 000 requests / 10 minutes per app)Sync failures for large groupsImplement batching and throttle-aware retry with Retry-After header
M365 group deleted externallyStale microsoftGroup reference, API errorsHealth check on group status; clear stale references on 404
Member sync conflicts (user exists in M365 but not in Equa)Incomplete sync, orphaned membersFlag unmatched members for admin review rather than auto-creating accounts