> ## 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 Setup Guide

> Purpose: Complete guide for setting up Microsoft Entra ID/Office 365 integration for PF-63.

**Purpose:** Complete guide for setting up Microsoft Entra ID/Office 365 integration for PF-63.

**Status:** ✅ Setup Complete (2026-01-28)

***

## Quick Start (5 Minutes)

### Prerequisites

* [x] Azure CLI installed (`az --version` works)
* [x] Azure account with Global Administrator or Application Administrator role
* [x] Supabase project linked (`npx supabase link --project-ref zkgxozahyczcnzpwhbbf`)
* [x] Supabase CLI available (via `npx supabase`)

### Automated Setup

**Windows:**

```powershell theme={null}
.\scripts\entra\create-app-registration.ps1
```

**Linux/macOS:**

```bash theme={null}
chmod +x scripts/entra/create-app-registration.sh
./scripts/entra/create-app-registration.sh
```

**Or use npm script:**

```bash theme={null}
npm run entra:setup
```

The script will:

1. Create app registration
2. Add API permissions
3. Generate client secret (save it when shown!)
4. Store secrets in Supabase
5. Generate admin consent URL
6. Create setup log

***

## Manual Setup Steps

### Step 1: Login to Azure

```bash theme={null}
az login
```

**Verify:**

```bash theme={null}
az account show
az account show --query tenantId --output tsv
```

Save the tenant ID - you'll need it.

### Step 2: Create App Registration

```bash theme={null}
az ad app create \
  --display-name "Encore Health OS - Entra ID Integration" \
  --sign-in-audience AzureADMyOrg \
  --web-redirect-uris "https://zkgxozahyczcnzpwhbbf.supabase.co/functions/v1/entra-oauth/callback"
```

**Capture the `appId` (Client ID)** from the output.

### Step 3: Add API Permissions

```bash theme={null}
APP_ID="<your-app-id>"

az ad app permission add \
  --id $APP_ID \
  --api 00000003-0000-0000-c000-000000000000 \
  --api-permissions df021288-bdef-4463-88db-98f22de89214=Role \
  --api-permissions 1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9=Role
```

**Permissions:**

* `df021288-bdef-4463-88db-98f22de89214` = User.ReadWrite.All (Application)
* `1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9` = LicenseAssignment.ReadWrite.All (Application)

### Step 4: Create Client Secret

```bash theme={null}
az ad app credential reset \
  --id $APP_ID \
  --years 2 \
  --display-name "Encore Health OS Integration Secret"
```

**⚠️ CRITICAL:** Capture the `password` value immediately - it's only shown once!

### Step 5: Store Secrets in Supabase

```bash theme={null}
# Link to production project
npx supabase link --project-ref zkgxozahyczcnzpwhbbf

# Store secrets
npx supabase secrets set ENTRA_TEST_APP_ID=<your-app-id>
npx supabase secrets set ENTRA_TEST_CLIENT_SECRET=<your-client-secret>
npx supabase secrets set ENTRA_TEST_TENANT_ID=<your-tenant-id>

# Verify
npx supabase secrets list
```

### Step 6: Grant Admin Consent

Generate the admin consent URL:

```bash theme={null}
TENANT_ID="<your-tenant-id>"
APP_ID="<your-app-id>"
REDIRECT_URI="https://zkgxozahyczcnzpwhbbf.supabase.co/functions/v1/entra-oauth/callback"

# PowerShell
$ENCODED_URI = [System.Uri]::EscapeDataString($REDIRECT_URI)
$ADMIN_CONSENT_URL = "https://login.microsoftonline.com/${TENANT_ID}/adminconsent?client_id=${APP_ID}&redirect_uri=${ENCODED_URI}"
Write-Host $ADMIN_CONSENT_URL

# Bash
ADMIN_CONSENT_URL="https://login.microsoftonline.com/${TENANT_ID}/adminconsent?client_id=${APP_ID}&redirect_uri=$(echo $REDIRECT_URI | jq -sRr @uri)"
echo $ADMIN_CONSENT_URL
```

**Visit the URL** and grant admin consent. You'll be redirected to the callback handler which will display a success message.

***

## Current Configuration

| Component              | Value                                                                        | Status       |
| ---------------------- | ---------------------------------------------------------------------------- | ------------ |
| **App ID (Client ID)** | `e02d8a52-e3e3-4569-a884-b7352619ec01`                                       | ✅ Active     |
| **Tenant ID**          | `894b815c-98a1-4651-b498-ce5122f9bfe6`                                       | ✅ Verified   |
| **Client Secret**      | Stored in Supabase secrets                                                   | ✅ Secure     |
| **Redirect URI**       | `https://zkgxozahyczcnzpwhbbf.supabase.co/functions/v1/entra-oauth/callback` | ✅ Configured |
| **Admin Consent**      | Granted (2026-01-28)                                                         | ✅ Complete   |
| **Project**            | Production (`zkgxozahyczcnzpwhbbf`)                                          | ✅ Linked     |

***

## Verification Checklist

Before starting implementation, verify:

* [x] Azure CLI installed and working
* [x] Logged in to Azure CLI
* [x] App registration created successfully
* [x] API permissions added (User.ReadWrite.All, LicenseAssignment.ReadWrite.All)
* [x] Client secret created and captured
* [x] Secrets stored in Supabase
* [x] Admin consent URL generated
* [x] Callback handler deployed (`entra-oauth` edge function)
* [x] Public access configured (`verify_jwt = false` in `config.toml`)
* [x] Admin consent granted

***

## Troubleshooting

### "Insufficient privileges"

* **Solution:** Ensure user has Global Administrator or Application Administrator role

### "App registration not found"

* **Solution:** Verify APP\_ID is correct, check with `az ad app list --display-name "Encore Health OS*"`

### "Permission not found"

* **Solution:** Verify permission IDs are correct, check Microsoft Graph API permission reference

### "Client secret not shown"

* **Solution:** Secret is only shown once. If lost, create new secret with `az ad app credential reset`

### "Missing authorization header" (401 error)

* **Solution:** Ensure `verify_jwt = false` is set in `supabase/config.toml` for `entra-oauth` function

***

## Security Notes

1. **Client Secret:** Only shown once during creation - save immediately
2. **Storage:** For testing, use Supabase secrets. For production, will use per-organization Vault storage
3. **Documentation:** Never commit client secrets to git
4. **Rotation:** Client secrets expire in 2 years - plan rotation before expiration

***

## Related Documentation

* **Gap Analysis:** archived at `docs/archive/integrations/ENTRA_ID_GAP_ANALYSIS.md` (superseded by PF-63 implementation)
* **Research Findings:** [ENTRA\_ID\_RESEARCH\_FINDINGS.md](./ENTRA_ID_RESEARCH_FINDINGS.md)
* **Overview:** [ENTRA\_ID\_OVERVIEW.md](./ENTRA_ID_OVERVIEW.md)
* **Specification:** `specs/pf/specs/PF-63-entra-id-integration.md`
* **Implementation Plan:** `specs/pf/plans/PF-63-entra-id-integration-PLAN.md`
* **Tasks:** `specs/pf/tasks/PF-63-TASKS.md`

***

**Last Updated:** 2026-01-28\
**Status:** ✅ Setup Complete - Ready for Implementation
