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

# Microsoft 365 Setup

> The Microsoft Entra app registration, permissions and credential that every Microsoft 365 connector shares

Onyx reads Microsoft 365 through three connectors: [SharePoint](/admins/connectors/official/microsoft-365/sharepoint),
which also covers OneDrive, [Microsoft Teams](/admins/connectors/official/microsoft-365/teams)
and [Outlook](/admins/connectors/official/microsoft-365/outlook).
All three sign in to Microsoft Graph as an application registered in Microsoft Entra, not as a user,
and they are set up the same way: register an application, grant it permissions, give Onyx a credential.
This page holds those shared steps. Each connector's page says what it needs beyond them.

One app registration can serve every connector. Grant it the union of the permissions in the table below,
or register one app per connector to keep the grants apart.

## Before you begin

You need:

* A Microsoft 365 tenant
* A Microsoft Entra user account holding the **Global Administrator** or **Privileged Role Administrator** role.
  The connectors need Microsoft Graph application permissions,
  and only these two roles can consent to those on behalf of your organization.
  **Application Administrator** and **Cloud Application Administrator** can register the app but cannot grant it
  consent.
* An Onyx administrator account
* A decision on how the connector authenticates, a client secret or a certificate.
  Changing it later means building a new credential and possibly re-indexing.

Some options need more: a Teams administrator for meeting transcripts, described on the Teams page,
and a SharePoint or Global Administrator when you [limit the app to specific
sites](#limiting-the-app-to-specific-sites).

## Choose an authentication method

Every connector accepts either a client secret or a certificate.

<Tip>
  Use a certificate if you need SharePoint permission sync or Teams channel files,
  or if your organization does not permit client secrets. Otherwise a client secret is quicker to set up.
</Tip>

|                                         | Client secret                                   | Certificate                                                          |
| --------------------------------------- | ----------------------------------------------- | -------------------------------------------------------------------- |
| Indexing files, pages, threads and mail | Yes                                             | Yes                                                                  |
| SharePoint permission sync              | **No**                                          | Yes                                                                  |
| Teams **Include Attachments**           | **No**                                          | Yes                                                                  |
| Teams and Outlook permission sync       | Yes                                             | Yes                                                                  |
| Setup effort                            | Lower. The portal generates the secret for you. | Higher. You create a certificate and upload part of it to Microsoft. |

SharePoint will not release its permission data, or the readers of a channel's files,
to an application that signed in with a secret, whatever permissions you grant it.

## Permissions

Every permission on this page is an **Application** permission and read only, with one exception:
**Sites.FullControl.All** on the **SharePoint** API.
SharePoint shows an item's access list only to an app with full control of the site.
Onyx reads with it and never writes to SharePoint.

| Connector and option                    | Microsoft Graph application permissions                                                                         | Also needed                                                                                                                                                                                                                            |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SharePoint and OneDrive files and pages | **Sites.Read.All**, or **Sites.Selected** with a `read` grant on each site                                      | Nothing                                                                                                                                                                                                                                |
| SharePoint **Auto Sync Permissions**    | **GroupMember.Read.All**, **Group.Read.All**, **Directory.Read.All**, **User.Read.All**, **Member.Read.Hidden** | A certificate credential, and **User.Read.All** on the **SharePoint** API, plus **Sites.FullControl.All** on the **SharePoint** API or, with **Sites.Selected**, a `fullcontrol` grant on each site.                                   |
| Teams channel threads (always on)       | **Team.ReadBasic.All**, **Channel.ReadBasic.All**, **ChannelMessage.Read.All**                                  | Nothing                                                                                                                                                                                                                                |
| Teams **Auto Sync Permissions**         | **ChannelMember.Read.All**, **User.Read.All**                                                                   | Nothing                                                                                                                                                                                                                                |
| Teams **Include Attachments**           | **Files.Read.All** or **Sites.Read.All**, **GroupMember.Read.All**, **User.Read.All**                           | A certificate credential, and **Sites.FullControl.All** on the **SharePoint** API or, with **Sites.Selected**, a `fullcontrol` grant on each channel site                                                                              |
| Teams **Include Inline Images**         | Nothing more                                                                                                    | Image extraction and analysis turned on in the Onyx search settings                                                                                                                                                                    |
| Teams **Include Meeting Transcripts**   | **OnlineMeetingTranscript.Read.All**, **OnlineMeetings.Read.All**, **User.Read.All**                            | The **Transcript API access** setting in the Teams admin center, and an application access policy granted to the meeting organizers. See [Microsoft Teams](/admins/connectors/official/microsoft-365/teams#configure-microsoft-teams). |
| Teams **Include Meeting Chats**         | **Chat.Read.All**, **User.Read.All**                                                                            | Nothing                                                                                                                                                                                                                                |
| Outlook mail (always on)                | **Mail.Read**, **User.Read.All**                                                                                | Nothing                                                                                                                                                                                                                                |
| Outlook **Include Calendar**            | **Calendars.Read**                                                                                              | Nothing                                                                                                                                                                                                                                |

<Note>
  A new registration already lists a delegated **User.Read** permission. The connectors never use it,
  since they sign in as an application rather than as a person. Leave it or remove it, as you prefer.
</Note>

## Register the application

<Steps>
  <Step title="Create the registration">
    Sign in to the [Microsoft Entra admin center](https://entra.microsoft.com)
    or the [Azure portal](https://portal.azure.com/) (`https://entra.microsoft.us` for GCC High or DoD)
    and go to **App registrations**. Select **New registration**, name it something recognizable,
    such as `Onyx Microsoft 365 Connector`, leave the supported account types and redirect URI at their defaults,
    and select **Register**.
  </Step>

  <Step title="Record the two IDs">
    On the application's **Overview** page, copy the **Application (client) ID** and the **Directory (tenant) ID**.
    Onyx asks for both, and the application access policy for Teams meeting transcripts needs the client ID.
  </Step>
</Steps>

## Grant permissions

The permissions come from two places in the portal, Microsoft Graph and SharePoint. Add them all first,
then grant consent once at the end.

<Steps>
  <Step title="Add the Microsoft Graph application permissions">
    Go to **API permissions → Add a permission → Microsoft Graph → Application permissions**,
    and add every Graph permission from the [table above](#permissions)
    for the connectors and options you plan to turn on. Select **Add permissions**.

    Add the grants for an option now if you expect to turn it on later, or come back and add them when you do.
    To limit the app to specific SharePoint sites, add **Sites.Selected** instead of **Sites.Read.All**.
    See [Limiting the app to specific sites](#limiting-the-app-to-specific-sites).
  </Step>

  <Step title="Add the SharePoint application permissions">
    Needed for SharePoint permission sync and for Teams **Include Attachments**.
    Select **Add a permission → SharePoint → Application permissions**, and add **Sites.FullControl.All**.
    SharePoint permission sync also needs **User.Read.All** here, to match access lists to the people in your directory.

    Add these under **SharePoint**, not Microsoft Graph. The two list permissions with the same names,
    and adding the Graph one by mistake is a common cause of permission sync failing later.
  </Step>

  <Step title="Grant admin consent">
    Select **Grant admin consent for \<your organization>** and confirm.
    Every permission in the list should then show **Granted**. Until you do this, none of them take effect.
    Grant consent again each time you add a permission later.

    This step needs the **Global Administrator** or **Privileged Role Administrator** role.
    No other role can consent to Microsoft Graph application permissions,
    so if the button is unavailable or consent fails, ask someone with one of those roles to do it.
  </Step>
</Steps>

<Note>
  Microsoft applies a new permission or consent within minutes, but not everywhere at once.
  It can take about half an hour before every sign-in carries the new permissions,
  so the same check in Onyx can pass and then fail. Wait and retry before you change anything else.
</Note>

## Create the credential

### Client secret

<Steps>
  <Step title="Open Certificates & secrets">
    In your app registration, go to **Certificates & secrets → Client secrets**.
  </Step>

  <Step title="Add a secret">
    Select **New client secret**, give it a description, and choose an expiry. Microsoft allows up to 24 months.
    Select **Add**.
  </Step>

  <Step title="Copy the value immediately">
    Copy the **Value** column, not the **Secret ID**. The value is shown only while you stay on this page.
    Once you navigate away you cannot get it back, and you have to create a new secret.
  </Step>
</Steps>

### Certificate

A certificate identifies the Entra application with a key file instead of a password. You need two files,
and both come from the same certificate:

* A **public certificate** (`.cer`, `.pem`, or `.crt`) that you upload to Entra ID
* A **`.pfx` file**, protected by a password, that you upload to Onyx

Sending the wrong file to the wrong place is the most common problem in this setup.
Either get a certificate from your organization's certificate authority, or create a self-signed one.

<Steps>
  <Step title="Generate the private key and certificate">
    ```bash theme={null}
    # Private key
    openssl genrsa -out onyx-m365.key 2048

    # Self-signed certificate, valid for two years
    openssl req -new -x509 -days 730 \
      -key onyx-m365.key \
      -out onyx-m365.crt \
      -subj "/CN=Onyx Microsoft 365 Connector"
    ```
  </Step>

  <Step title="Package the private key as a .pfx">
    ```bash theme={null}
    openssl pkcs12 -export \
      -inkey onyx-m365.key \
      -in onyx-m365.crt \
      -out onyx-m365.pfx
    ```

    You are prompted for an export password. Set one and record it: Onyx does not accept an empty password,
    asks for it later, and cannot recover it.
  </Step>

  <Step title="Check what you have">
    | File            | Goes to                                        |
    | --------------- | ---------------------------------------------- |
    | `onyx-m365.crt` | Entra ID                                       |
    | `onyx-m365.pfx` | Onyx                                           |
    | `onyx-m365.key` | Neither. Keep it somewhere safe, or delete it. |

    Store the `.pfx` and its password securely.
  </Step>

  <Step title="Upload the public certificate to Entra">
    In your app registration, go to **Certificates & secrets → Certificates**, select **Upload certificate**,
    choose `onyx-m365.crt`, add a description, and select **Add**.
  </Step>
</Steps>

<Note>
  If your certificate authority issues you a `.pfx` only,
  extract the public half for Entra with `openssl pkcs12 -in yourcert.pfx -clcerts -nokeys -out yourcert.crt`.
</Note>

<Warning>
  Entra takes `.cer`, `.pem`, and `.crt` files only. Uploading the `.pfx` fails with *Upload a certificate (public key)
  with one of the following file types: .cer, .pem, .crt*. The `.pfx` goes to Onyx, not to Entra.
</Warning>

### Enter the credential in Onyx

Each connector asks for a credential when you add it. Select an existing credential from the list,
or select **Create New**, pick the tab for your authentication method, and enter the details from your app registration:

* **Client Secret** tab: the **Application (client) ID**, the **Directory (tenant) ID** and the secret **Value** you
  copied
* **Certificate Authentication** tab: the two IDs, the `.pfx` in the **Private Key (PFX)** field and the export
  password you set in the **Certificate Password** field. Each field is labelled with the connector's name.

Onyx keeps credentials per connector type, so the list on the SharePoint form shows SharePoint credentials only.
To use one app registration for several connectors, enter the same IDs and secret or certificate once per connector.

## Limiting the app to specific sites

By default the app holds **Sites.Read.All**, which lets it read every SharePoint site in the tenant,
even when a connector names only one. If that is too broad,
grant **Sites.Selected** instead and authorize the app one site at a time. The app can read nothing until you do.
This applies to both authentication methods, to a user's OneDrive, which is a site of its own,
and to the SharePoint sites behind Teams channel files.

The role you grant depends on what the connector does:

| Connector use                            | Role to grant on each site | Entra permission also needed                                                                                                                      |
| ---------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| SharePoint indexing only                 | `read`                     | Microsoft Graph → **Sites.Selected**                                                                                                              |
| SharePoint indexing with permission sync | `fullcontrol`              | Microsoft Graph → **Sites.Selected**. The per-site grant replaces tenant-wide **Sites.FullControl.All** on the SharePoint API.                    |
| Teams **Include Attachments**            | `fullcontrol`              | Microsoft Graph → **Files.Read.All**, which the connector needs to read channel files. Private and shared channels each have a site of their own. |

Permission sync and Teams channel files need `fullcontrol` because SharePoint shows an item's access list only to an app
that has full control of the site. Onyx never writes to SharePoint.

<Accordion title="Granting a site to the app">
  You need a Global Administrator or SharePoint Administrator account.
  The steps below use [Microsoft Graph Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer).
  You can do the same with [PnP
  PowerShell](https://pnp.github.io/powershell/cmdlets/Grant-PnPAzureADAppSitePermission.html)
  (`Grant-PnPAzureADAppSitePermission`).

  <Steps>
    <Step title="Sign in and consent">
      Sign in to Graph Explorer,
      then select your profile icon → **Consent to permissions** and enable **Sites.FullControl.All**.
      This lets Graph Explorer grant site permissions. It grants nothing to your Onyx application.
    </Step>

    <Step title="Find the site ID">
      Run a **GET** request, substituting your tenant and site name:

      ```
      GET https://graph.microsoft.com/v1.0/sites/contoso.sharepoint.com:/sites/YourSiteName?$select=id
      ```

      For a OneDrive, the site is `contoso-my.sharepoint.com:/personal/jane_contoso_com`.
      Copy the `id` from the response. It is a three-part value such as `contoso.sharepoint.com,5a58bb09-…,9f2ec1da-…`.
    </Step>

    <Step title="Grant the role">
      Change the method to **POST**, using the site ID you just copied:

      ```
      POST https://graph.microsoft.com/v1.0/sites/{site-id}/permissions
      ```

      Send this body. Set `roles` to `["read"]` for indexing only, or `["fullcontrol"]` for permission sync.
      Set `id` to your Onyx application's **Application (client) ID**.

      ```json theme={null}
      {
        "roles": ["read"],
        "grantedToIdentities": [
          {
            "application": {
              "id": "00000000-0000-0000-0000-000000000000",
              "displayName": "Onyx Microsoft 365 Connector"
            }
          }
        ]
      }
      ```

      A successful grant returns `201 Created`.
    </Step>

    <Step title="Verify">
      Change the method back to **GET** on the same URL,
      and confirm the role you granted appears against your application.

      ```
      GET https://graph.microsoft.com/v1.0/sites/{site-id}/permissions
      ```
    </Step>
  </Steps>

  Repeat the last three steps for every site the connector indexes.
</Accordion>

## National clouds

Each connector has **Authority Host** and **Graph API Host** under its advanced settings,
and the SharePoint connector has **SharePoint Domain Suffix** as well. All must describe the same cloud.
Onyx rejects an authority host that does not match the Graph host when you save,
and corrects a domain suffix that does not match the Graph host with a warning in its log.

| Cloud                    | Authority Host                      | Graph API Host                            | Domain Suffix    |
| ------------------------ | ----------------------------------- | ----------------------------------------- | ---------------- |
| Commercial               | `https://login.microsoftonline.com` | `https://graph.microsoft.com`             | `sharepoint.com` |
| US Government (GCC High) | `https://login.microsoftonline.us`  | `https://graph.microsoft.us`              | `sharepoint.us`  |
| US Government (DoD)      | `https://login.microsoftonline.us`  | `https://dod-graph.microsoft.us`          | `sharepoint.us`  |
| China (21Vianet)         | `https://login.chinacloudapi.cn`    | `https://microsoftgraph.chinacloudapi.cn` | `sharepoint.cn`  |
| Germany                  | `https://login.microsoftonline.de`  | `https://graph.microsoft.de`              | `sharepoint.de`  |

## Rotating the secret or certificate

Indexing stops when the secret or certificate expires. To rotate without downtime:

<Steps>
  <Step title="Add the new one alongside the old">
    In **Certificates & secrets**, add a new client secret and copy its value, or upload the new public certificate.
    Entra holds more than one at a time, and both work until the old one expires.
  </Step>

  <Step title="Update the credential in Onyx">
    In **Admin Panel → Existing Connectors**,
    open the credential of each connector that uses this app registration and replace the secret value,
    or the `.pfx` and its password.
  </Step>

  <Step title="Delete the old one">
    Once an indexing attempt has succeeded, delete the previous secret or certificate in Entra.
  </Step>
</Steps>

## Troubleshooting

Credential, consent and certificate problems, with the message each connector shows for them.
Each connector's page lists the problems that are its own.

<AccordionGroup>
  <Accordion title="invalid_client, Invalid or expired Microsoft Teams credentials, Microsoft rejected the client secret or certificate, or an error that names AADSTS7000215 or AADSTS7000222">
    Entra does not recognize the secret or certificate, or it belongs to another app registration. For a secret,
    check that you copied the **Value** rather than the **Secret ID**, and that it has not passed its expiry date.
    For a certificate, it has usually expired,
    or the `.pfx` and the uploaded public certificate came from different certificates.
    Create a new one and update the credential.
  </Accordion>

  <Accordion title="Microsoft does not know this directory">
    The directory ID or the authority host is wrong. For a national cloud,
    set every host from the same row of [National clouds](#national-clouds).
  </Accordion>

  <Accordion title="Upload a certificate (public key) with one of the following file types">
    You uploaded the `.pfx` to Entra. Upload the `.crt`, `.cer`, or `.pem` instead, and keep the `.pfx` for Onyx.
  </Accordion>

  <Accordion title="Failed to load certificate, or The PFX bundle could not be opened">
    Onyx could not open the `.pfx`, usually because the password is wrong or the file is not a `.pfx` at all.
    Repeat [Certificate](#certificate).
  </Accordion>

  <Accordion title="Unsupported app only token">
    SharePoint permission sync or Teams channel files are running on a client secret credential,
    and SharePoint will not release permission data to an app that signed in with a secret.
    Check which credential the connector is attached to, and rebuild it with a [certificate](#certificate).
  </Accordion>

  <Accordion title="Permissions show as not granted">
    Admin consent was never given, or was given before you added the last permission.
    Select **Grant admin consent** again.
  </Accordion>

  <Accordion title="A permission shows Granted but Microsoft still answers 403">
    The permission was added on the wrong API. SharePoint checks its own **Sites.FullControl.All**,
    and a Graph permission with the same name does not count.
  </Accordion>

  <Accordion title="A setup check passes, then fails minutes later">
    Microsoft is still applying a permission, consent or application access policy change.
    Wait about half an hour and retry before you change anything else.
  </Accordion>

  <Accordion title="Indexing worked, then stopped on a fixed date">
    The secret or certificate expired. See [Rotating the secret or certificate](#rotating-the-secret-or-certificate).
  </Accordion>
</AccordionGroup>
