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

# SharePoint Online

> Deploy your Cobalt agent on a SharePoint Online intranet — anonymously, or with silent single sign-on.

# Deploy your Cobalt agent to SharePoint Online

Put a Cobalt agent on your **SharePoint Online (modern)** intranet so people get
help on the pages they already use. The agent runs in the top-level page (not an
iframe), so it behaves exactly like the Cobalt web widget on any other site.

<Note>
  **SharePoint Online (modern) only.** SharePoint on-premises and classic pages
  are not supported. You always need a **SharePoint tenant admin** (App Catalog

  * Script sources). Single sign-on additionally needs a **Microsoft Entra
    admin** (to consent to Cobalt's app — once per tenant). Plan \~20 minutes for
    the anonymous path, \~40 for SSO.
</Note>

You download the SharePoint package itself from the agent's channel **Install**
tab in the Cobalt console — this guide is the instructions that go with it.

## Choose how users are identified

Pick this on the channel **before** you deploy; you can change it later.

|                     | **Anonymous** (recommended to start)                                        | **Federated SSO** (advanced)                                                  |
| ------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| End-user experience | No login; an anonymous visitor session                                      | Recognized as their signed-in Microsoft 365 user, **no second login**         |
| Setup               | Just deploy the package                                                     | Deploy **+** consent to Cobalt's Entra app **+** configure token verification |
| Features            | **Full** — chat, **file/screenshot uploads, dictation, and voice** all work | Same, plus the conversation is bound to the employee's verified identity      |
| Entra admin needed  | No                                                                          | Yes (one consent, once per tenant)                                            |

If you just want a working agent on SharePoint, **use Anonymous** — it's the
fastest path and supports the entire composer (attachments, dictation, voice).
Add SSO later when you want conversations attributed to the signed-in employee.

## How it works

Cobalt ships a small **SharePoint Framework (SPFx)** package. Its web part sets
`window.cobaltSettings` and injects Cobalt's widget loader (`loader.js`) from the
Cobalt widget host, in the top-level page. For SSO it *also* silently acquires
the signed-in user's Microsoft Entra token and forwards it; Cobalt verifies that
token against your tenant's identity provider and binds the conversation to the
employee.

**One package, no per-customer build.** The SSO token is requested for **Cobalt's
own multi-tenant Entra application** — the same app for every customer. The
package holds **no secret**; you never register your own app or rebuild the
`.sppkg`. You consent to Cobalt's app once, and configure Cobalt to trust tokens
from *your* tenant.

<Note>
  The production Cobalt widget host is **`https://widget.cobalt.peoplereign.io`**.
  Use it everywhere below, including the Trusted Script Source. One caveat: the
  current package (v1.0.2) still *defaults* its **Widget source URL** to Cobalt's
  dev host, so set that property explicitly to
  `https://widget.cobalt.peoplereign.io/loader.js` when you configure the web
  part or extension (called out again in the steps below). A package update will
  flip the default.
</Note>

## Prerequisites & roles

* A Cobalt **web-widget channel** (create or reuse one).
* **SharePoint tenant admin** — to upload + deploy the package in the App Catalog
  **and** add the widget host as a Trusted Script Source.
* **Microsoft Entra admin** — **SSO only**: to admin-consent Cobalt's application
  in your tenant (once).
* **Owner/Admin** in the Cobalt console — channel + token-verification config is
  admin-only.

## 1. Configure the channel in Cobalt

In the Cobalt console, open the web-widget channel and set these **before you
deploy:**

1. **Identity mode** — **Anonymous** or **Federated SSO**, per the table above.
2. **Allowed origins** — add your SharePoint origin: `https://<tenant>.sharepoint.com`
   (or the wildcard `https://*.sharepoint.com`, which also covers the `-my` /
   OneDrive host). **Required** — Cobalt refuses the widget's config fetch and
   chat connection from any origin you haven't listed (you'll otherwise see a
   `403`). A bare `*` is not accepted.
3. Copy the **Channel Key** from the **Install** tab — you'll paste it into the
   web part in Step 5.

## 2. Download the package from the Install tab

In the channel's **Install** tab, set **Deploy to → SharePoint site**, then
download the versioned package (currently `cobalt-agent-widget-1.0.2.sppkg`). The
Install tab is the only place the package is distributed.

## 3. Upload + deploy to the App Catalog

1. Go to your tenant App Catalog:
   `https://<tenant>.sharepoint.com/sites/appcatalog`.
2. Open **Apps for SharePoint** and **upload** the `.sppkg`.
3. In the trust dialog, review and click **Deploy**.
4. Leave **Make this solution available to all sites in the organization**
   checked (the package uses `skipFeatureDeployment`) so the web part and
   site-wide launcher are available tenant-wide without per-site installs.

## 4. Add the widget host as a Trusted Script Source

**This is the step people miss.** SharePoint Online enforces a modern-page
**Content Security Policy**. The widget's `loader.js` is an external script, so
SharePoint blocks it under `script-src` unless a tenant admin adds the widget
host as a **Trusted Script Source** — once per tenant.

<Tabs>
  <Tab title="Admin center">
    1. Open the **SharePoint admin center**.
    2. Go to **Advanced → Script sources**.
    3. **Add source** → `https://widget.cobalt.peoplereign.io` → **Save**.
    4. Effective within a few minutes — hard-refresh the page afterward.
  </Tab>

  <Tab title="PowerShell">
    ```powershell theme={null}
    Add-SPOContentSecurityPolicy -Source "https://widget.cobalt.peoplereign.io"
    Get-SPOContentSecurityPolicy
    ```
  </Tab>
</Tabs>

<Tip>
  Add the **domain** (`https://widget.cobalt.peoplereign.io`), not the exact
  `loader.js` URL — the loader pulls hashed bundle assets + fonts from the same
  host, and a domain-level entry covers them. Bare wildcards (`*`) and
  leading-label wildcards (`*.domain`) are **rejected**; a subdomain wildcard such
  as `*.cobalt.peoplereign.io` is **allowed**.
</Tip>

## 5. Add the agent to a page

Both surfaces ship in the **same** package.

<Tabs>
  <Tab title="Web part (per-page)">
    1. Edit a page → **+** → add the **"Cobalt Agent"** web part.
    2. In the property pane, paste the **Channel Key** (from the Install tab) and
       set **Widget source URL** to
       `https://widget.cobalt.peoplereign.io/loader.js` (the v1.0.2 package
       pre-fills Cobalt's dev host — see the note above). Leave **Token
       resource** at its default — it's pre-filled for Cobalt's Entra app.
    3. **Publish** the page.
  </Tab>

  <Tab title="Application Customizer (site-wide)">
    1. Add the app to the site; the floating launcher appears on every page.
    2. Set the **Channel Key** in the extension property, and set **Widget source
       URL** to `https://widget.cobalt.peoplereign.io/loader.js` (see the note
       above). Token resource defaults correctly — no other input needed.
  </Tab>
</Tabs>

At this point an **Anonymous** channel is done — open a page and the launcher is
there. For SSO, continue.

## 6. (SSO only) Consent to Cobalt's app + configure verification

A **federated-identity** channel needs two one-time actions: consent to Cobalt's
Entra application in your tenant, and tell Cobalt to trust tokens from your
tenant. You do **not** register your own app or change the package.

### 6a. Admin-consent Cobalt's application (once per tenant)

A Microsoft Entra **Global Admin** grants tenant-wide consent to Cobalt's
multi-tenant app (client id **`956f530e-a3a7-41b7-b4c3-0baf77760c2b`**). This
provisions the app's service principal in your tenant so SharePoint can silently
obtain a token for it.

<Tabs>
  <Tab title="PowerShell (recommended)">
    ```powershell theme={null}
    Connect-MgGraph -Scopes "Application.ReadWrite.All","DelegatedPermissionGrant.ReadWrite.All"

    # Provision Cobalt's app in your tenant
    New-MgServicePrincipal -AppId "956f530e-a3a7-41b7-b4c3-0baf77760c2b"

    # Authorize SharePoint's client to call it (the grant the API-access page makes)
    $client   = Get-MgServicePrincipal -Filter "displayName eq 'SharePoint Online Client Extensibility Web Application Principal'"
    $resource = Get-MgServicePrincipal -Filter "appId eq '956f530e-a3a7-41b7-b4c3-0baf77760c2b'"
    New-MgOauth2PermissionGrant -ClientId $client.Id -ConsentType "AllPrincipals" `
      -ResourceId $resource.Id -Scope "user_impersonation"
    ```
  </Tab>

  <Tab title="Admin consent URL">
    A Global Admin opens (replacing the tenant id with yours):

    ```
    https://login.microsoftonline.com/<your-tenant-id>/adminconsent?client_id=956f530e-a3a7-41b7-b4c3-0baf77760c2b
    ```

    Then **SharePoint admin center → Advanced → API access** → **approve** the
    pending request for Cobalt's app.
  </Tab>
</Tabs>

<Note>
  Order matters: the app's service principal must exist in your tenant (the
  consent / `New-MgServicePrincipal` step) **before** the SharePoint API-access
  request will resolve. If API access shows *"The requested permission isn't
  valid"*, the app hasn't been provisioned yet — do 6a first, then re-check. The
  PowerShell grant above performs the same authorization the API-access page
  would, and sidesteps it entirely.
</Note>

### 6b. Configure token verification in Cobalt

In the Cobalt console: **Settings → SSO → End-user token verification** →
**Federated identity** (`federated_oidc`):

| Field                 | Value                                                                                                                                                                                  |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Issuer URL**        | `https://login.microsoftonline.com/<your-tenant-id>/v2.0`                                                                                                                              |
| **JWKS URI**          | `https://login.microsoftonline.com/<your-tenant-id>/discovery/v2.0/keys`                                                                                                               |
| **Allowed audiences** | `api://956f530e-a3a7-41b7-b4c3-0baf77760c2b` **and** the bare client id `956f530e-a3a7-41b7-b4c3-0baf77760c2b` (list both — Entra issues one or the other depending on token version). |
| **Email claim**       | `preferred_username` — see the note below.                                                                                                                                             |

<Note>
  **Set the email claim to `preferred_username`, not `email`.** Cobalt reads the
  **single** claim you name here — there is **no fallback** to other claims. By
  default an Entra **v2.0** access token (which is what SharePoint issues for
  Cobalt's app) carries the user's UPN in **`preferred_username`** and does
  **not** include an `email` claim, so naming `email` makes every verified token
  fail with "user isn't recognized". `preferred_username` is the UPN
  (e.g. `jane@contoso.com`) and is present by default. *(If you specifically need
  the mailbox address instead of the UPN, add `email` as an
  [optional claim](https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims)
  on Cobalt's app registration and only then set this field to `email`.)*
</Note>

<Warning>
  **Allowed audiences** is the load-bearing security control: Cobalt only accepts
  tokens whose `aud` is one you list. Never list a broad audience like Microsoft
  Graph. The **issuer** is what scopes acceptance to *your* tenant — set it to
  your tenant id.
</Warning>

## 7. Verify it works

Open a SharePoint page and confirm:

* The launcher loads, and a test message round-trips.
* **(SSO)** No sign-in prompt, popup, or redirect; the agent recognizes you.

To check the SSO token directly, open the page in a **fresh incognito window**
(so there's no stale token cache), sign in, then in the console:

```js theme={null}
const t = await window.cobaltSettings.getToken();
JSON.parse(atob(t.split(".")[1]));   // inspect aud + iss
```

`aud` must be in your **Allowed audiences** and `iss` must match your **Issuer**.

## 8. Troubleshooting

| Symptom                                                                            | Cause                                                                                                      | Fix                                                                                                                                                                                                                                             |
| ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Widget never loads; console shows a `script-src` CSP violation                     | Widget host not a Trusted Script Source                                                                    | Add `https://widget.cobalt.peoplereign.io` (Step 4).                                                                                                                                                                                            |
| Widget never loads; console shows a `403` origin error                             | SharePoint origin not in the channel's **Allowed origins**                                                 | Add `https://<tenant>.sharepoint.com` (or `https://*.sharepoint.com`) — Step 1.                                                                                                                                                                 |
| `404` config / channel error                                                       | Wrong or missing Channel Key                                                                               | Re-copy the **Channel Key** from the Install tab.                                                                                                                                                                                               |
| Loader runs but the chat can't connect / image thumbnails don't load               | Tenant CSP restricts `connect-src` to the Cobalt API host (no admin-center control, unlike Script sources) | Rare on default SharePoint CSP. If your tenant locks down `connect-src`, contact Cobalt support.                                                                                                                                                |
| **(Voice)** "Voice mode could not start the microphone"                            | Microphone permission denied, or the browser/OS blocked mic access for the site                            | Allow microphone access when the browser prompts; check the site isn't mic-blocked in browser/OS settings, then reload.                                                                                                                         |
| **(SSO)** API access: *"The requested permission isn't valid"*                     | Cobalt's app isn't provisioned in your tenant yet, **or** you're looking at a stale request                | Do **Step 6a** (provision + grant) first; reject any stale request; the new one then resolves. The PowerShell grant in 6a bypasses this page entirely.                                                                                          |
| **(SSO)** Console / Network shows `AADSTS65001` ("access blocked / not consented") | Admin consent for Cobalt's app is missing                                                                  | Complete **Step 6a** (admin consent / `New-MgServicePrincipal` + grant).                                                                                                                                                                        |
| **(SSO)** `getToken()` returns *"Token request previously failed"*                 | A cached failure from an earlier attempt — it isn't retrying                                               | Retest in a **fresh incognito window** (or clear the site's `msal.*` storage). The cache masks the real error.                                                                                                                                  |
| **(SSO)** Connects but the user isn't recognized                                   | Token `aud`/`iss` mismatch, or the configured **Email claim** isn't in the token                           | Decode the token (Step 7); fix **Allowed audiences** / **Issuer** to match. If `aud`/`iss` are correct, set **Email claim** to **`preferred_username`** (v2.0 Entra tokens carry the UPN there and have no `email` claim by default — Step 6b). |

## Updates & maintenance

Branding and Cobalt product updates apply **automatically** on the next page load
— no re-deploy. You only re-download + re-deploy when Cobalt publishes a **new
package version** (a loader-contract, property-schema, or SPFx-framework change).
Routine agent, branding, and greeting changes never require a repackage. Because
SSO uses Cobalt's shared app, **Cobalt rotating or updating that app never
requires you to rebuild or redeploy** — at most you re-consent.

## Not recommended: the Embed web part (iframe)

SharePoint's built-in **Embed** web part renders an iframe. Cobalt does not expose
a cross-origin framable surface, and an iframe breaks silent SSO and storage
partitioning — defeating the "don't sign in again" value. Use the SPFx package
above.
