# SharePoint

## What it does

The SharePoint integration lets Speedwave read and edit the files, pages, and lists on one SharePoint site through Microsoft Graph. You pick the site when you connect it, and Speedwave stays inside that site for the life of the integration: it can upload a document, publish a page, or add a list column, but it has no path to any other site in your tenant.

## What Speedwave can do

Speedwave has 28 tools here, covering files, pages, lists, and identity. None take a site parameter: every call uses the `site_id` baked into the worker. Destructive tools cannot be undone.

| Tool | What it does |
| --- | --- |
| `listFileIds` | Lists files and folders under a path (defaults to the site root). |
| `getFileFull` | Reads a file's full metadata, with content loaded on demand. |
| `downloadFile` | Downloads a SharePoint file to a local path under `/workspace`. |
| `uploadFile` | Uploads a local file to a SharePoint path; supports `expectedEtag`, `createOnly`, or `overwrite` to control conflicts. |
| `listPages` | Lists the site's pages. |
| `getPage` | Reads a page's layout and content. |
| `createPage` | Creates a new page. |
| `updatePage` | Replaces a page's full layout (Graph has no partial update). |
| `addWebPart` | Adds one of 13 standard web part types to a page. |
| `updateWebPart` | Updates an existing web part's data. |
| `removeWebPart` | Removes a web part from a page. |
| `publishPage` | Publishes a draft page so it becomes visible. |
| `addImageWebPart` | Adds an image web part from an image already uploaded to the site. |
| `generateTableOfContents` | Scans a page's headings and builds a linked list from them. |
| `listLists` | Lists the site's lists. |
| `getList` | Reads a list's definition. |
| `createList` | Creates a new list. Needs `Sites.Manage.All`. |
| `updateList` | Renames or reconfigures a list. |
| `deleteList` | Deletes a list. Destructive. |
| `addListColumn` | Adds a typed column to a list. Needs `Sites.Manage.All`. |
| `removeListColumn` | Removes a column from a list. Destructive. |
| `listItems` | Lists items in a list, with optional OData `$filter`. |
| `getItem` | Reads a single item. |
| `createItem` | Creates a new item. |
| `updateItem` | Updates an existing item. |
| `deleteItem` | Deletes an item. Destructive. |
| `deletePage` | Deletes a page. Destructive. |
| `getCurrentUser` | Returns the id, display name, email, and user principal name of the signed-in account. |

Local paths for `downloadFile` and `uploadFile` must resolve under `/workspace`, and a denylist blocks `.git`, `.env`, `.speedwave`, `.ssh`, `.npmrc`, `.docker`, and `.kube` inside it.

## What it consists of

A SharePoint worker runs in its own container, holding two files mounted read-only at `/tokens/`: an access token and the site ID it is bound to. A host-side OAuth worker owns the longer-lived credentials, client ID, tenant ID, and refresh token, in a project-scoped file the container never mounts. If either mounted file is missing or empty, the worker starts with no client and the integration stays inactive rather than failing loudly.

- ~/.speedwave/oauth/&lt;project&gt;/
  - sharepoint.json host-only OAuth state: clientId, tenantId, refreshToken
- /tokens/ mounted read-only into the worker
  - access_token
  - site_id

## How it works

Sign-in happens once, through an OAuth device-code flow. You authorize the app in a browser, and Speedwave stores the resulting tokens on the host. The host-side OAuth worker then keeps the SharePoint worker supplied with a fresh access token, so the container never sees the refresh token. The worker refreshes proactively near expiry and reactively on a Graph `401`, and every tool call carries the worker's own `site_id` from `/tokens/site_id`.

```mermaid
flowchart LR
  A[SharePoint worker] -->|needs fresh token| B[Host OAuth worker]
  B -->|refresh_token| C[Microsoft /oauth2/v2.0/token]
  C -->|new access_token| D["/tokens/access_token"]
  D -->|re-read| A
```

## Set it up

Connecting SharePoint needs an Azure AD app registration. Follow the general integration flow in [connect an integration](/docs/guides/connect-an-integration/), then come back here for three SharePoint-specific values: `client_id`, `tenant_id`, and `site_id`.

`site_id` must be a Microsoft Graph site ID, not a browser URL, so use one of these two forms.

```text title="site_id"
acme.sharepoint.com:/sites/Marketing:
```

Note the colon at the start and the colon at the end.

```text title="site_id"
{hostname},{site-guid},{web-guid}
```

1. Open Settings and find the SharePoint integration card.
2. Enter `client_id`, `tenant_id`, and `site_id`.
3. Start the connection. Speedwave runs the device-code flow and shows a device code and a Microsoft URL.
4. Open the URL, enter the code, and sign in with an account that has access to the site. Approve the requested permissions.
5. When sign-in finishes, Speedwave writes the tokens to the host and the SharePoint worker becomes available.

<DesktopFrame screen="integrations" />
**Admin consent:** The integration requests `Sites.Manage.All`, `Files.ReadWrite.All`, `User.Read`, and `offline_access`. `Sites.Manage.All` is required for creating lists and usually needs a tenant administrator to grant admin consent in Azure AD. Without it, list creation fails.

## Security boundaries

Speedwave works through Microsoft Graph only, and only against the site the worker was bound to at setup. It cannot edit site navigation, since Microsoft Graph does not publish those endpoints, so navigation changes stay in the SharePoint UI. The container never holds the refresh token, only a short-lived access token it cannot renew on its own. For where these files live and why each worker only ever sees its own service's credentials, see [how credentials are handled](/docs/security/credentials/).