> Raw Markdown twin (generated at build time from the source Markdown). Rendered page: https://docs.gatellm.io/en/howto/deploy-office-addin · Doc index: https://docs.gatellm.io/en/llms.txt


# Deploy the Office add-in

The add-in has two deployment forms: local sideload is only for development verification; production goes through centralized distribution in the M365 admin center. See [Office / Microsoft 365 add-in](/en/usecases/office-m365-addin.md) for the background and capability overview.

## Prerequisites

- **Get the deployment package**: the `gatellm-for-msft-365-localhost` package is provided by GateLLM to contracted customers and is **not publicly downloadable**; if you haven't obtained it, first reach out via the [official product page](https://www.gatellm.io/office-addin). The package is a self-contained directory containing `start.sh` / `sideload.sh` (local start and install), `scripts/build-manifest.mjs` (manifest generation), `webroot/` (a pre-built scrubbed SPA), `templates/` (manifest templates), `commands/` (all operation guides: consent, Entra app, access_policies, troubleshooting, etc.). All commands below run inside the package directory.
- **Node.js 18+**.
- **mkcert** (`brew install mkcert`): signs a locally trusted TLS certificate; see pitfall 1 for why you can't use an openssl self-signed certificate.
- **Gateway address (public domain + trusted HTTPS certificate) + API key**: see the quick-deployment pages (e.g. [Docker single node](/en/quickstart/docker-single-node.md)) for how to run the gateway. **Note: a gateway running on localhost cannot be used for the add-in** — the gateway must be deployed at an address with a public domain + trusted CA certificate, see the warning below and pitfall 2.
- **(As needed) an Entra app registered in your own tenant**: needed when using `entra_scope` / `gateway_auth_source=entra`, or when not using the default multi-tenant app, see "Register your own Entra app" below.

::: warning A localhost gateway cannot be used for add-in testing
Even if you run an HTTPS gateway locally (with a locally trusted certificate), the Office WebView still can't connect — this has been field-tested to fail. A local gateway can only verify the gateway itself; end-to-end validation of the add-in requires first deploying the gateway to an address with a **public domain + trusted CA certificate** (a staging environment is fine), then pointing `GATEWAY_URL` at it.
:::

## Local sideload (development verification)

1. Configure gateway credentials:
   ```bash
   cp .env.example .env   # fill in GATEWAY_URL (an HTTPS address on a public domain, cannot be localhost) and GATEWAY_TOKEN
   ```
2. Start and install:
   ```bash
   ./start.sh            # reads .env → signs the cert → generates the manifest → starts the HTTPS service
   ./sideload.sh         # installs the office (TaskPane) manifest
   ./sideload.sh --outlook   # or installs the outlook (Mail) manifest
   ./sideload.sh --clear     # uninstall
   ```
3. **Acceptance**: quit and reopen Excel / Word / PowerPoint → **Insert → My Add-ins** shows Gatellm (confirms successful loading; end-to-end conversation with a model still requires the gateway to be on a public domain, see the warning above).

> Sideload uses a self-signed certificate, and Office is more lenient with `localhost`; opening `https://localhost:8443` in a browser shows a certificate warning, which is normal.

## Production: centralized distribution via the M365 admin center

Production deployment splits in two halves: **the SPA onto a CDN** and **the manifest uploaded to the M365 admin center**.

1. **Host the SPA**: statically host the package's `webroot/` directory onto your CDN (S3 + CloudFront, Azure Static Web Apps, nginx, etc.).
2. **Generate the production manifest** (pointing `taskpane_url` at the CDN origin):
   ```bash
   node scripts/build-manifest.mjs office manifests/manifest-office.xml \
     taskpane_url=https://gatellm-addin.your-cdn.example \
     gateway_url=https://llm-gateway.your-org.example \
     entra_sso=1 graph_client_id=<guid> gateway_auth_source=entra
   ```
   The two hosts are **two independent add-ins** (the Office version TaskPaneApp / the Outlook version MailApp, with different permission models): generate each manifest, upload each, and version each separately. If deploying Outlook too, generate another one with `outlook`.
3. **Validate the manifest**:
   ```bash
   npx --yes office-addin-manifest validate manifests/manifest-office.xml
   ```
4. **Upload**: M365 Admin Center → Settings → **Integrated apps** → **Upload custom apps**. **Acceptance**: the user opens the add-in in Office and can enter a conversation directly.

Production hard requirements:

- The manifest's `<SourceLocation>` must be **publicly reachable HTTPS + a real trusted CA certificate** (not self-signed).
- HTTPS throughout, and the `.js` / `.mjs` in the SPA must be served with the `text/javascript` MIME type.

## Outlook / Entra admin consent

There are two kinds of consent, mutually independent:

| Consent | When needed | Who does it |
|------|---------|------|
| Entra SSO consent | `entra_sso=1` and using the **default multi-tenant app** | Global Admin, once per tenant |
| Microsoft Graph consent (mail / calendar) | Required when deploying the **Outlook manifest** (independent of `entra_sso`) | Global Admin, once per tenant |

- **Default multi-tenant app**: the package's `commands/consent.md` gives the corresponding one-time consent URL; the Global Admin opens it in an already-logged-in browser and clicks Accept. Without this step, every user hits "Need admin approval" on first open; after completion you can verify the service principal has entered the tenant with `az ad sp show` (command in the same guide).
- **Using your own Entra app** (set `graph_client_id`): the consent URL above does not apply — consent is managed directly on your own app, see the next section.
- **Policy forbids granting third-party apps**: register your own single-tenant Entra app, grant the same set of Graph delegated permissions (`Mail.ReadWrite` / `Calendars.Read` / `People.Read` / `User.Read` / `offline_access`) and do admin consent, then pass its client ID as `graph_client_id` into the Outlook manifest. The data flow is unchanged; only the approval object becomes your app.

::: warning Not all deployments need Entra consent
A static gateway / Vertex organization-level config without `entra_sso=1` does not use Entra SSO consent; but as long as you deploy Outlook, Graph consent is still required.
:::

## Register your own Entra app

Setting any of `graph_client_id` (Outlook), `entra_scope`, `gateway_auth_source=entra` requires registering an app in **your own tenant**. The checklist is below; full steps and troubleshooting (`AADSTS50011` / `AADSTS65001`, etc.) are in the package's `commands/entra-app.md`:

1. Entra admin center → **App registrations** → **New registration** (single-tenant). Minimal form: one app acts as both the login client and the token resource.
2. **Redirect URIs** (registered under the **SPA platform**, not Web / Mobile), both derived from the add-in's load origin (self-hosted = your taskpane origin):
   - SPA: `https://<your-origin>/msal-redirect.html`
   - NAA broker: `brk-multihub://<your-host>` (write only the origin's **host part** — no scheme prefix, no path; with a port, include the port; assembled by the Office host at runtime from the load origin). Example: when the load origin is `https://gatellm-addin.your-cdn.example`, register `brk-multihub://gatellm-addin.your-cdn.example`; when the origin has a port (e.g. `https://addin.example:8443`), register `brk-multihub://addin.example:8443`.
   Missing either one gives `AADSTS50011` on login.
3. **Expose an API** (required for `entra_scope` / `gateway_auth_source=entra`): set the Application ID URI to `api://<app-guid>` → add a scope (e.g. `access_as_user`, allowing admin consent) → in *API permissions* grant that scope as a delegated permission to the app itself. If deploying Outlook, additionally add Microsoft Graph delegated permissions (list in the previous section).
4. **Grant admin consent** (*Grant admin consent for \<tenant\>*). Miss this step and every user sees the consent dialog, or is directly rejected when user consent is disabled.
5. In the app's **Manifest**, set `"accessTokenAcceptedVersion": 2` (only when you did step 3 Expose an API). Without it, Entra issues a v1.0 token (`iss` without `/v2.0`, no `preferred_username`), which most JWT middleware rejects by default.

The gateway validates `iss` / `aud` / `scp` on this token (JWKS signature verification); see [Configure SSO enterprise login](/en/howto/configure-sso.md) for how to configure the gateway.

## Six pitfalls checklist

Each item below has been field-tested in the package README's troubleshooting table, ordered by deployment sequence:

1. **The certificate must use mkcert**. An openssl self-signed certificate is rejected by the Office WebView, reporting `Add-in Error — can't load the add-in`. After `brew install mkcert`, run `mkcert -install` to install the local CA into the system trust store.

2. **`GATEWAY_URL` must be a "public domain + trusted HTTPS certificate"; localhost won't do.** ① An `http://` gateway is blocked locally by the Office WebView's mixed-content policy, appearing as `Could not reach gateway` in the add-in, and the gateway monitors no requests at all (the request was never sent); ② a gateway started on localhost, even over HTTPS with a locally trusted certificate, still can't be reached by the Office WebView in practice — a local gateway can't do end-to-end testing for the add-in and must be deployed to an address with a public domain + trusted CA certificate.

3. **Opening `https://localhost:8443` in a browser and being redirected to `gatellm.io/downloads` is normal.** This is the SPA's host detection — finding "not inside an Office host" it guides a download. The add-in must be opened inside Office, not in a browser.

4. **The CDN must satisfy three points**: serve `.js` / `.mjs` as the `text/javascript` MIME type; set the directory index to `index.html`; configure SPA fallback to return unknown paths to `index.html` (for `/auth/callback`). Otherwise chunks 404 / MIME errors.

5. **All runtime fetch targets must allow CORS.** The response headers of `bootstrap_url`, `mcp_servers[].url`, `skills[].url`, and `otlp_endpoint` must allow the taskpane origin:
   ```
   Access-Control-Allow-Origin: https://gatellm-addin.your-cdn.example
   ```

6. **Re-uploading the same `<Id>` with the same `<Version>` is silently ignored.** The M365 Admin Center caches by ID + Version; change the fourth segment of `<Version>` (e.g. `1.0.0.9` → `1.0.0.10`) and upload again.

## Next steps

- [Office / Microsoft 365 add-in](/en/usecases/office-m365-addin.md) for capabilities, governance, and the data plane.
- On the gateway side, authenticate / bill by real users, together with [Configure SSO enterprise login](/en/howto/configure-sso.md).
