SharePoint / OneDrive Source
What it ingests
Documents from SharePoint document libraries — and, when you opt in, from users' personal OneDrive libraries. Each file becomes one CreativeWork in the ontology, attributed to whoever last modified it, so the graph links the people writing documents to the people shipping code and running meetings.
Body text is extracted from text-like formats (.md, .txt, .csv, .json, .html, …). Other files — including Office .docx / .pptx / .xlsx, which are ZIP containers rather than text — still land as an entity with their title, URL, author and library, just without a body.
Site pages, SharePoint lists, and sharing/permission signals are out of scope.
Credential
References the same microsoft_graph credential as the Microsoft Teams source — a JSON object describing an Entra ID app registration:
{
"tenant_id": "72f988bf-86f1-41af-91ab-2d7cd011db47",
"client_id": "a1b2c3d4-e5f6-4789-8abc-def012345678",
"client_secret": "abc8Q~…"
}Already running the Teams source? Reuse that credential.
Point this source at the same vault row. A tenant that has connected Teams does not need a second app registration — only two additional consented permissions on the one it already has (below). That is why the credential type was named for Graph rather than for Teams.
Config fields
| Key | Required | Notes |
|---|---|---|
site_ids | no | Site URLs or site IDs to ingest, newline- or semicolon-separated. Blank crawls every site in the tenant. |
cloud | no | global (default) for commercial Microsoft 365 — including GCC, which is served by the commercial endpoints — usgov for GCC-High (L4), or usgovdod for DoD (L5). |
file_extensions | no | Comma-separated extensions to restrict ingestion to (e.g. md, pdf, docx). Blank ingests every file. |
include_personal_sites | no | true to also crawl every user's personal OneDrive. Off by default — see below. |
Do not separate site_ids with commas
A SharePoint site ID is itself a comma-joined triple:
contoso.sharepoint.com,bf6fb551-d508-4946-a439-b2a6154fc1d9,65a04b8b-1f44-442b-a1fc-9e5852fb946cThat is the exact string Graph returns, so it is the one you are most likely to paste. Splitting on commas would shred it into three unusable fragments, so this field splits on newlines and semicolons instead. Plain site URLs (https://contoso.sharepoint.com/sites/Engineering) work too and are easier to read.
About include_personal_sites
Graph's tenant-wide site enumeration returns each user's personal OneDrive alongside the team sites, flagged isPersonalSite. Crawling them multiplies the job by your headcount and reaches into individual employees' document stores, so Corveil skips them unless you ask. Turn it on deliberately, and expect the first crawl to take considerably longer.
Provider-side setup
1. Use (or create) the app registration
If you already configured the Teams source, reuse that app registration and skip to step 2. Otherwise follow the Teams guide's app-registration steps — the registration itself is identical; only the permissions differ.
2. Add application permissions and grant admin consent
In Entra ID → App registrations → your app → API permissions, add these Application (not Delegated) permissions and click Grant admin consent:
| Permission | Why |
|---|---|
Sites.Read.All | Enumerate the tenant's sites |
Files.Read.All | List document libraries, read their changes, download file bodies |
Both are ✅ available in GCC-High (L4) and DoD (L5), as are every endpoint this source calls.
Why not Sites.Selected?
It looks like the least-privilege option and is not viable for a crawler. It is a three-part AND — Entra consent, plus a per-site permission grant, plus a token — the granting application needs Sites.FullControl.All, and every enumeration endpoint (/sites, /sites/getAllSites, /sites/delta, /sites?search=) accepts only Sites.Read.All or Sites.ReadWrite.All. It fits "the customer nominates N sites and hands us the IDs out of band", not discovery. If per-site opt-in matters to you, list those sites in site_ids instead — the scope is then the same, with a permission model Graph supports.
3. GCC-High / DoD tenants
L4 and L5 are different hosts. Set cloud to usgov for GCC-High and usgovdod for DoD:
cloud | Graph host | Token scope |
|---|---|---|
usgov | graph.microsoft.us | https://graph.microsoft.us/.default |
usgovdod | dod-graph.microsoft.us | https://dod-graph.microsoft.us/.default |
Both authenticate against login.microsoftonline.us. A token minted for one resource is rejected by the other and by the commercial endpoint, so the cloud value has to match the tenant. Plain GCC (not GCC-High) is served by the commercial endpoints — use global there.
Site enumeration uses GET /sites/getAllSites rather than GET /sites for a second reason beyond national clouds: the plain /sites collection is geo-scoped, so on a multi-geo tenant it silently returns only the sites in the caller's geography — a healthy-looking source missing half the company.
Wire-up
POST /api/sensors
Whole tenant:
{
"sensor_type": "sharepoint",
"name": "Contoso SharePoint",
"config": {},
"credentials": { "graph_credential": "<microsoft_graph credential id>" }
}Specific sites, text documents only:
{
"sensor_type": "sharepoint",
"name": "Engineering docs",
"config": {
"site_ids": "https://contoso.sharepoint.com/sites/Engineering\nhttps://contoso.sharepoint.com/sites/Architecture",
"file_extensions": "md, txt, pdf, docx"
},
"credentials": { "graph_credential": "<microsoft_graph credential id>" }
}GCC-High:
{
"sensor_type": "sharepoint",
"name": "Agency SharePoint",
"config": { "cloud": "usgov" },
"credentials": { "graph_credential": "<microsoft_graph credential id>" }
}Verify
Run Test connection. It enumerates the sites in scope and lists each one's document libraries, so a missing consent or a mistyped site URL fails here rather than silently ingesting nothing.
A partially-working configuration is reported without stopping the source: if one site of five cannot be read, the other four keep ingesting and the source's status line names the offending site. Sources only begin polling once you confirm their bindings.
Notes and limits
The first crawl drains across several polls. There is no tenant-wide file delta in Graph, so the source walks each library's own change feed and stores one resume link per library. When a library is larger than one poll's page budget, the source stores the point it reached and continues from there on the next tick — so the first crawl of a large tenant fills in progressively rather than arriving as one enormous poll or restarting from the top each time.
Files are tracked by id, not by path. Graph's delta feed omits the path on parentReference and reports each item's latest state rather than every individual change, so a moved or renamed file is the same document to Corveil, not a new one.
Expired change tokens resync automatically. After a long gap Graph can invalidate a library's resume link (HTTP 410). The source treats that as an instruction to re-enumerate that library, not as an error.
Deleted files are not removed from the ontology. Deletions are recognized and skipped — a removed document is never re-ingested — but entities already created from it remain.
Author emails come from the file, not from a directory lookup. SharePoint usually reports the last modifier's email on the item itself. When it does not, the document still ingests with a display name and simply does not link to a Corveil user.
Sharing and permission signals are out of scope. Graph exposes them through Prefer: deltashowsharingchanges, which requires Sites.FullControl.All — a permission that would dominate a government security review for a read-only intelligence connector.