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

# Microsoft copilot

# Microsoft 365 Copilot — Setup

Registering the Entra application this integration authenticates as.

Requires an admin who can grant tenant-wide consent: **Cloud Application
Administrator**, **Application Administrator**, or **Global Administrator**.
(Global Admin is only needed for permissions that enable privilege escalation —
`RoleManagement.ReadWrite.Directory`, `AppRoleAssignment.ReadWrite.All` — and
neither is used here.)

***

## Step 0 — Be in the right directory

**This is the step most setups get wrong**, and it fails silently: consent
granted in the wrong directory succeeds there and changes nothing where you
need it.

1. In the Azure portal, click your avatar (top right) → **Switch directory**
2. Select the tenant you intend to connect
3. Go to **Microsoft Entra ID → Overview** and confirm the **Tenant ID** shown
   matches the one you will enter in g360

***

## Step 1 — Open (or create) the app registration

1. Portal search → **App registrations**
2. Open the **All applications** tab — the default view only lists apps you own,
   so an app created by a colleague will not appear under "Owned applications"
3. Search for the Client ID, or **+ New registration**:
   * **Name:** anything, e.g. `g360 Copilot Analytics`
   * **Supported account types:** *Accounts in this organizational directory only*
   * **Redirect URI:** leave blank — this is a daemon app with no user sign-in
4. On **Overview**, confirm **Directory (tenant) ID** matches Step 0

> If Directory (tenant) ID does not match the tenant you want data from, the app
> lives somewhere else. Either register a new app in the correct tenant, or make
> this one multi-tenant and consent into the target tenant explicitly.

***

## Step 2 — Add the permissions

1. Left nav → **API permissions**

2. **+ Add a permission** → **Microsoft Graph**

3. Choose **Application permissions** — *not* Delegated

   This is the second most common mistake. Delegated permissions act on behalf
   of a signed-in user; this integration authenticates as itself with no user
   present, so delegated permissions are inert in it.

4. Tick both:

   | Permission         | Needed for                                                                       |
   | ------------------ | -------------------------------------------------------------------------------- |
   | `Reports.Read.All` | The Copilot usage and user-count reports. **Mandatory.**                         |
   | `User.Read.All`    | The directory sync — department, job title, and account status. Enrichment only. |

5. **Add permissions**

The `User.Read` (Delegated) entry Azure adds automatically to every new
registration can stay — it is unused and harmless. Note it is *not* the same as
`User.Read.All`: it reads only the signed-in user's own profile.

***

## Step 3 — Grant admin consent

1. Still on **API permissions**, click **Grant admin consent for \<Tenant Name>**
2. Confirm **Yes**
3. Every row's **Status** should turn to a green ✅ *Granted for \<Tenant>*

**Read the tenant name in that button.** It names the directory consent will be
written to. If it is not the tenant you expect, stop — you are in the wrong
directory and Step 0 was missed.

Granting consent is also what creates the **service principal**. Until it exists,
Entra will not issue a token at all, failing with `AADSTS7000229` — see
[TROUBLESHOOTING](#troubleshooting).

### If the button is greyed out

Your account lacks the role. Either ask an admin, or have them open:

```
https://login.microsoftonline.com/<TENANT-ID>/adminconsent?client_id=<CLIENT-ID>
```

***

## Step 4 — Create a client secret

1. Left nav → **Certificates & secrets** → **Client secrets** → **+ New client secret**
2. Set a description and expiry
3. **Copy the `Value` column immediately.**

   The table shows two columns. **Value** is the secret. **Secret ID** is an
   identifier and will not authenticate — pasting it produces `AADSTS7000215`.
   The Value is displayed only once; once you navigate away it cannot be
   retrieved, and you must create a new secret.

***

## Step 5 — Verify the service principal exists

1. **Microsoft Entra ID → Enterprise applications → All applications**
2. Search for the Client ID

It must appear here. *App registrations* lists application definitions;
*Enterprise applications* lists the service principals that can actually
authenticate. A row in the first without a row in the second is exactly the
`AADSTS7000229` state.

***

## Step 6 — Connect in g360

**Integration → LLM → Microsoft 365 Copilot → Connect**

| Field         | Where to find it                                      |
| ------------- | ----------------------------------------------------- |
| Tenant ID     | App registration → Overview → Directory (tenant) ID   |
| Client ID     | App registration → Overview → Application (client) ID |
| Client Secret | The **Value** from Step 4                             |

Click **Test**, then save. Assign the connection to a **project** — the
analytics endpoints resolve connections by project and will 404 without one.

Then sync:

```bash theme={null}
manage.py sync_m365_copilot --run-now one --connection-id <id> --inline
```

`--inline` runs in-process, so failures appear in your terminal rather than a
worker log.

***

## Troubleshooting

| Error                              | Cause                                        | Fix                                    |
| ---------------------------------- | -------------------------------------------- | -------------------------------------- |
| `AADSTS7000215`                    | Secret **ID** pasted instead of **Value**    | Step 4                                 |
| `AADSTS7000229`                    | No service principal — consent never granted | Step 3, verify Step 5                  |
| `AADSTS7000222`                    | Secret expired                               | New secret, Step 4                     |
| `AADSTS700016`                     | Client ID not in this tenant                 | Step 1 — check Directory (tenant) ID   |
| `AADSTS90002`                      | Tenant ID does not exist                     | Step 0                                 |
| `403` on reports                   | `Reports.Read.All` missing or not consented  | Steps 2–3                              |
| Connects, no data                  | Tenant holds no Copilot licences             | Expected — sync reports `skipped`      |
| Empty leaderboard, aggregates fine | Tenant conceals user names in reports        | M365 admin centre → Reports → Settings |

### A note on concealed names

Microsoft 365 can anonymise user names in all admin reports. When enabled, Graph
returns hex digests instead of UPNs, and per-user Copilot attribution becomes
impossible — the integration detects this and says so rather than showing an
empty leaderboard. Seat and adoption figures are unaffected.

Turn it off at **Microsoft 365 admin centre → Settings → Org settings → Reports
→** untick *Display concealed user, group, and site names in all reports*.
