> ## Documentation Index
> Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Entra ID Integration - Research Findings

> Date: 2026-01-28 Research Method: Microsoft Learn MCP Server Status: ✅ Research Complete

**Date:** 2026-01-28\
**Research Method:** Microsoft Learn MCP Server\
**Status:** ✅ Research Complete

***

## Executive Summary

Research confirms that **Azure App Registration CAN be automated programmatically** using Microsoft Graph API. This enables Encore Health OS to automatically provision Entra ID integration for organizations without manual Azure Portal steps.

***

## Key Findings

### 1. ✅ Programmatic App Registration is Possible

**Microsoft Graph API Endpoint:**

```
POST /applications
```

**Required Permissions:**

* **Delegated:** `Application.ReadWrite.All` (requires admin user)
* **Application:** `Application.ReadWrite.OwnedBy` or `Application.ReadWrite.All`

**Capabilities:**

* ✅ Create application registration programmatically
* ✅ Generate client secret during creation (via `passwordCredentials`)
* ✅ Configure API permissions (`requiredResourceAccess`)
* ✅ Set redirect URIs, sign-in audience, etc.

**Example Request:**

```http theme={null}
POST https://graph.microsoft.com/v1.0/applications
Content-Type: application/json

{
  "displayName": "Encore Health OS - Organization Name",
  "passwordCredentials": [
    {
      "displayName": "Encore Health OS Integration Secret"
    }
  ],
  "requiredResourceAccess": [
    {
      "resourceAppId": "00000003-0000-0000-c000-000000000000", // Microsoft Graph
      "resourceAccess": [
        {
          "id": "df021288-bdef-4463-88db-98f22de89214", // User.ReadWrite.All
          "type": "Role"
        },
        {
          "id": "...", // LicenseAssignment.ReadWrite.All
          "type": "Role"
        }
      ]
    }
  ],
  "signInAudience": "AzureADMyOrg" // Single-tenant
}
```

**Response Includes:**

* `id` - Application object ID
* `appId` - Client ID (application ID)
* `passwordCredentials[0].secretText` - Client secret (only shown once!)

### 2. ⚠️ Admin Consent Requirements

**Finding:** Admin consent CAN be granted programmatically, but requires:

1. **Privileged Role Administrator** or **Global Administrator** role
2. **Microsoft Graph API** to grant app roles:
   ```
   POST /servicePrincipals/{servicePrincipalId}/appRoleAssignedTo
   ```

**Alternative Approaches:**

**Option A: Programmatic Grant (Requires Admin User)**

* User with admin role calls Microsoft Graph API
* Grants permissions via `AppRoleAssignment.ReadWrite.All`
* Fully automated but requires admin user session

**Option B: Admin Consent URL (One-Time Manual Step)**

* Generate admin consent URL: `https://login.microsoftonline.com/{tenant}/adminconsent?client_id={appId}`
* Admin visits URL once to grant consent
* After consent, app can use application permissions

**Option C: Hybrid Approach (Recommended)**

* Automate app registration
* Generate admin consent URL
* Store URL in organization settings
* Admin visits URL once to complete setup
* After consent, full automation enabled

### 3. Service Principal Creation

**Finding:** Service principal is automatically created when app registration is created.

**Microsoft Graph API:**

```
POST /servicePrincipals
{
  "appId": "{application-client-id}"
}
```

**Note:** Service principal is typically auto-created, but can be explicitly created if needed.

### 4. Permission Grant Programmatically

**Application Permissions (App Roles):**

```http theme={null}
POST /servicePrincipals/{servicePrincipalId}/appRoleAssignedTo
Content-Type: application/json

{
  "principalId": "{clientServicePrincipalId}",
  "resourceId": "{microsoftGraphServicePrincipalId}",
  "appRoleId": "{permissionId}"
}
```

**Required Permissions for Granting:**

* `AppRoleAssignment.ReadWrite.All` (delegated, requires admin)
* Or use admin consent URL (one-time manual step)

### 5. Multi-Tenant Considerations

**Finding:** Each organization needs its own app registration in their Entra ID tenant.

**Architecture Options:**

**Option 1: Per-Organization App Registration (Recommended)**

* Each organization has own app registration in their tenant
* Encore Health OS stores app credentials per organization
* Most secure, follows Microsoft best practices
* Requires organization admin to grant consent

**Option 2: Single Multi-Tenant App (Not Recommended)**

* One app registration shared across all organizations
* Requires complex consent management
* Security concerns with shared credentials
* Not suitable for healthcare/PHI scenarios

**Recommendation:** Use Option 1 (per-organization app registration)

***

## Implementation Strategy

### Phase 1: Automated App Registration

**Workflow:**

1. Organization admin enables Entra ID integration in Encore Health OS
2. Encore Health OS calls Microsoft Graph API to create app registration
3. App registration created with required permissions
4. Client ID and secret stored in Supabase Vault (encrypted)
5. Admin consent URL generated and displayed to admin
6. Admin visits URL to grant consent
7. After consent, integration is fully active

**Edge Function:** `entra-register-app`

* Creates app registration via Microsoft Graph
* Configures required permissions
* Generates client secret
* Returns admin consent URL

### Phase 2: Admin Consent Flow

**Option A: Automated (If Admin User Available)**

* Use admin user's session to grant consent programmatically
* Requires admin to sign in to Encore Health OS with admin role
* Fully automated after initial admin sign-in

**Option B: Manual One-Time Step (Recommended)**

* Generate admin consent URL
* Display in UI with instructions
* Admin visits URL once
* After consent, integration active

**Recommendation:** Start with Option B (manual consent), add Option A later if needed

### Phase 3: User Provisioning

**After App Registration Complete:**

* Use stored client ID and secret
* Authenticate via client credentials flow
* Create users via `POST /users`
* Assign licenses via `POST /users/{id}/assignLicense`

***

## Security Considerations

### 1. Credential Storage

* ✅ Store client secrets in Supabase Vault (encrypted)
* ✅ Never log secrets or expose in API responses
* ✅ Rotate secrets periodically (Microsoft Graph supports secret rotation)

### 2. Permission Scope

* ✅ Use least-privilege permissions
* ✅ Only request permissions actually needed
* ✅ Document why each permission is required

### 3. Admin Consent

* ⚠️ Admin consent grants powerful permissions
* ✅ Require explicit admin action (not automatic)
* ✅ Log all consent grants for audit trail
* ✅ Provide clear explanation of permissions requested

### 4. Multi-Tenant Isolation

* ✅ Each organization's credentials isolated
* ✅ RLS policies enforce tenant isolation
* ✅ No cross-organization credential access

***

## API Endpoints Required

### App Registration

* `POST /applications` - Create app registration
* `GET /applications/{id}` - Get app details
* `PATCH /applications/{id}` - Update app
* `DELETE /applications/{id}` - Delete app

### Service Principal

* `POST /servicePrincipals` - Create service principal (usually auto-created)
* `GET /servicePrincipals/{id}` - Get service principal
* `POST /servicePrincipals/{id}/appRoleAssignedTo` - Grant app role

### Admin Consent

* Admin consent URL: `https://login.microsoftonline.com/{tenant}/adminconsent?client_id={appId}`
* Or programmatic: `POST /oauth2PermissionGrants` (for delegated permissions)

### User Provisioning (After Setup)

* `POST /users` - Create user
* `POST /users/{id}/assignLicense` - Assign license
* `PATCH /users/{id}` - Update user
* `DELETE /users/{id}` - Delete user

***

## Code Examples

### Create App Registration with Secret

```typescript theme={null}
// Edge function: entra-register-app
const response = await fetch('https://graph.microsoft.com/v1.0/applications', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${adminToken}`, // Admin user token
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    displayName: `Encore Health OS - ${organizationName}`,
    passwordCredentials: [
      {
        displayName: 'Encore Health OS Integration Secret',
        endDateTime: new Date(Date.now() + 2 * 365 * 24 * 60 * 60 * 1000).toISOString(), // 2 years
      },
    ],
    requiredResourceAccess: [
      {
        resourceAppId: '00000003-0000-0000-c000-000000000000', // Microsoft Graph
        resourceAccess: [
          {
            id: 'df021288-bdef-4463-88db-98f22de89214', // User.ReadWrite.All
            type: 'Role',
          },
          {
            id: '...', // LicenseAssignment.ReadWrite.All
            type: 'Role',
          },
        ],
      },
    ],
    signInAudience: 'AzureADMyOrg', // Single-tenant
  }),
});

const app = await response.json();
// app.appId = Client ID
// app.passwordCredentials[0].secretText = Client Secret (save immediately!)
```

### Generate Admin Consent URL

```typescript theme={null}
const adminConsentUrl = `https://login.microsoftonline.com/${tenantId}/adminconsent?client_id=${appId}&redirect_uri=${encodeURIComponent(redirectUri)}`;
```

### Grant Admin Consent Programmatically (If Admin User Available)

```typescript theme={null}
// Get Microsoft Graph service principal
const graphSp = await fetch(
  `https://graph.microsoft.com/v1.0/servicePrincipals?$filter=displayName eq 'Microsoft Graph'&$select=id,appRoles`
).then(r => r.json());

// Find permission IDs
const userReadWriteAll = graphSp.value[0].appRoles.find(
  r => r.value === 'User.ReadWrite.All'
);

// Grant app role
await fetch(
  `https://graph.microsoft.com/v1.0/servicePrincipals/${clientServicePrincipalId}/appRoleAssignedTo`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${adminToken}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      principalId: clientServicePrincipalId,
      resourceId: graphSp.value[0].id,
      appRoleId: userReadWriteAll.id,
    }),
  }
);
```

***

## Limitations & Constraints

### 1. Admin Consent Required

* ⚠️ Cannot fully automate without admin user session
* ✅ Can automate app registration
* ✅ Can generate consent URL
* ⚠️ Admin must visit URL or grant via API (requires admin session)

### 2. Permission Requirements

* ⚠️ Creating app registrations requires `Application.ReadWrite.All`
* ⚠️ Granting app roles requires `AppRoleAssignment.ReadWrite.All`
* ✅ Both can be delegated permissions (admin user signs in)
* ⚠️ Or use admin consent URL (one-time manual step)

### 3. Secret Retrieval

* ⚠️ Client secret only shown once during creation
* ✅ Must store immediately in secure vault
* ⚠️ Cannot retrieve secret later (must create new one)

### 4. Multi-Tenant Complexity

* ⚠️ Each organization needs own app registration
* ✅ Can automate per organization
* ⚠️ Requires organization's Entra ID tenant access

***

## Recommendations

### 1. Hybrid Approach (Recommended)

* ✅ Automate app registration
* ✅ Generate admin consent URL
* ✅ Store credentials securely
* ⚠️ Require one-time admin consent (manual step)
* ✅ After consent, full automation enabled

### 2. User Experience Flow

1. Org admin enables Entra ID integration in Encore Health OS
2. Encore Health OS creates app registration automatically
3. Display admin consent URL with clear instructions
4. Admin visits URL and grants consent
5. Integration active, user provisioning automated

### 3. Future Enhancement

* Add option for admin to sign in to Encore Health OS with admin role
* Use admin session to grant consent programmatically
* Fully automated flow (no manual URL visit)

***

## References

### Microsoft Learn Documentation

* [Create Application API](https://learn.microsoft.com/en-us/graph/api/application-post-applications)
* [Grant Admin Consent Programmatically](https://learn.microsoft.com/en-us/entra/identity/enterprise-apps/grant-admin-consent)
* [Grant API Permissions Programmatically](https://learn.microsoft.com/en-us/graph/permissions-grant-via-msgraph)
* [Application Permissions](https://learn.microsoft.com/en-us/graph/permissions-reference#application-permissions)

### Related Encore Health OS Documentation

* Entra ID Gap Analysis (archived; superseded by PF-63 — see `docs/archive/integrations/ENTRA_ID_GAP_ANALYSIS.md`)
* [Entra ID Implementation Summary](./ENTRA_ID_OVERVIEW.md)

***

**Document Version:** 1.0\
**Last Updated:** 2026-01-28\
**Research Method:** Microsoft Learn MCP Server
