---
name: microsoft-onedrive-oauth-app
description: >-
  Registers a Microsoft Entra ID application for OneDrive and the Microsoft
  Graph files APIs. Builds on the `microsoft-entra-app-registration` base
  skill; read that first. This skill covers only what OneDrive adds: the
  `Files.*` permissions and which "Selected" scopes are current, why
  `Files.*.All` reaches every user's OneDrive and every SharePoint site,
  OneDrive personal versus for Business and what that forces on the
  account-types choice, drive and driveItem addressing, upload sessions, delta
  sync, sharing links, and per-user throttling. Use when asked to get OneDrive
  OAuth credentials, connect OneDrive or OneDrive for Business, or debug a
  OneDrive connector returning `403 accessDenied`, `404` on a user's drive, or
  failed large-file uploads. For SharePoint sites or `Sites.Selected` use
  `microsoft-sharepoint-oauth-app`; for plain Microsoft sign-in use
  `microsoft-oauth-app`.
---

# OneDrive (Microsoft Graph files) OAuth2 App Registration

Get a working OAuth2 client for OneDrive — an Entra ID app registration with the right `Files.*` permissions — for a
platform that connects many customers' drives.

Registering the app is the base skill's job. What OneDrive adds is a permission family with a wide blast radius and a
narrow set of least-privilege escapes. **`Files.Read.All` and `Files.ReadWrite.All` are not "OneDrive" permissions**:
in application mode they reach every file in every site collection in the tenant, which includes every employee's
private OneDrive *and* every SharePoint document library. The three narrower models — a delegated token scoped to one
signed-in user, the app folder, and per-item `Files.SelectedOperations.Selected` grants — each cost something at
onboarding. Choosing among them is the whole negotiation; the portal work is twenty minutes.

## Built on: `microsoft-entra-app-registration`

**Read the base skill first.** It is the source of truth for the Entra mechanics this one assumes:

- **Supported account types** — single tenant vs multitenant vs personal Microsoft accounts, the permission ceilings
  each imposes (30 permissions once consumer accounts are in scope), and that application permissions do not exist
  for a consumer-only audience. OneDrive is the one Microsoft product where this dropdown is a *product* decision (§3).
- **Redirect URIs** — the Web vs SPA vs public-client platform choice, exact case-sensitive matching, the count and
  length limits, and the Unified.to callback hosts.
- **Delegated vs application permissions, and admin consent** — how the two modes differ, which permissions need an
  admin, and that Microsoft Graph *application* permissions require a **Privileged Role Administrator**, not an
  Application Administrator.
- **Client secrets and certificates** — the 24-month cap, the **Value** shown exactly once, `AADSTS7000222` on
  expiry, add-then-delete rotation, and the per-cloud authority and Graph hosts (commercial, US Gov L4/L5, China).
- **`offline_access`, publisher verification and the generic AADSTS symptom table** — no `Files.*` scope carries a
  refresh token of its own; `offline_access` is what gets you one, and a file-sync connector is worthless without it.

The base also holds the inputs to collect, the run order, tenant ownership, the credential hand-off and the generic
stop-and-ask conditions. **A reader who loads only this file is missing all of that** — every portal path, every
consent rule, and every credential-handling rule this skill silently relies on. Everything below is OneDrive-specific.

## Extra inputs to collect

On top of the base skill's batch:

| Input | Notes |
| --- | --- |
| **Whose files? One signed-in user's drive, or every drive in the tenant?** | The decisive question — it picks delegated vs application and narrow vs `.All` (§1, §2) |
| **OneDrive for Business only, or consumer OneDrive too?** | Changes supported account types, and caps the app at 30 permissions (§3) |
| **Read-only, or read/write?** | Decides the verb, and whether uploads and sharing-link creation are in scope (§5, §6) |
| **Does the connector write files larger than 250 MB?** | Forces upload sessions, and in app-only mode a *different* permission (§5) |
| **Does it need sharing links or per-item permissions?** | Sharing is priced and throttled separately from file I/O (§6, §7) |
| **Is a scanning/sync model intended (delta over many drives)?** | Drives the throttling budget and the app-only decision (§5, §7) |

## Platform state (verified 2026-09-20 — re-verify before trusting)

- **Microsoft Graph is the API for all three file backends.** OneDrive (personal), OneDrive for Business and
  SharePoint document libraries are the same `drive` / `driveItem` resources; the `driveType` property comes back as
  `personal`, `business` or `documentLibrary`. There is no separate "OneDrive API" to register against.
- **`Files.Read.Selected` and `Files.ReadWrite.Selected` are legacy — do not use them.** Both are still listed in the
  permissions reference, both are marked **(Preview)**, both are delegated-only, and Microsoft states they are "only
  valid on work or school accounts", are "only exposed for working with Office 365 file handlers (v1.0)", and
  "should not be used for directly calling Microsoft Graph APIs". They grant access for a few hours after a user
  picks a file. They are **not** the per-item least-privilege model, despite the name.
- **`Files.SelectedOperations.Selected` is the current per-item model**, and it supports **both delegated and
  application** modes. Unlike the two above, it requires **admin consent in both modes**. It is the file-level member
  of the same Selected family as `Sites.Selected` (see the SharePoint skill) and works the same way: consent grants
  nothing until someone stamps a grant on a specific item.
- **`Files.ReadWrite.AppFolder` still exists in both modes**, giving an app a private folder inside the user's drive
  and nothing else. The delegated form is marked (Preview) and is available for consent on personal Microsoft
  accounts. Reaching it via `/me/drive/special/approot` is **delegated-only** — the special-folder API documents
  application permissions as "Not supported."
- **Microsoft's own permission tables disagree about app-only drive access.** `GET /drives/{id}` (and `/users/{id}/drive`)
  documents Application as "Not supported.", while the OneDrive scanning guidance tells app-only scanners to enumerate
  every user's drive with `Files.Read.All`. Treat the scanning guidance as the intent, verify app-only drive access
  against a real tenant during §8, and report what you actually observe rather than quoting either page.
- **OneDrive and SharePoint share one throttling budget** — the same resource-unit economics, measured per app per
  tenant. OneDrive adds *per-user* limits the SharePoint skill does not cover (§7).

If the Entra admin center or Graph does not behave like this, stop and report what you actually see.

## 1. The `Files.*` family

Requested as Microsoft Graph permissions, in roughly the order a customer security review will tolerate them:

| Permission | Modes | What it reaches |
| --- | --- | --- |
| `Files.ReadWrite.AppFolder` | delegated + application | Only the app's own folder inside a drive. Nothing else. |
| `Files.SelectedOperations.Selected` | delegated + application | **Nothing until an item-level grant is stamped** (§2). Admin consent required in **both** modes. |
| `Files.Read` | delegated only | The signed-in user's files. No admin consent. On personal accounts, also files shared *with* that user. |
| `Files.ReadWrite` | delegated only | Read/create/update/delete the signed-in user's files. No admin consent. |
| `Files.Read.All` | delegated + application | Delegated: everything the signed-in user can already see. **Application: every file in every site collection, admin consent required.** |
| `Files.ReadWrite.All` | delegated + application | Same reach, read/write. The broadest ask in this family. |
| `Files.Read.Selected` / `Files.ReadWrite.Selected` | delegated only | **Legacy.** Preview, work/school only, Office 365 file handlers only — not for calling Graph (Platform state). |

Identity-only scopes (`openid`, `profile`, `email`, `offline_access`, `User.Read`) carry no file access whatsoever.

**Delegated is the default answer for a per-user connector.** `Files.Read` and `Files.ReadWrite` need no
administrator at all, which means an ordinary employee can click through your connect flow — the single biggest
difference between a OneDrive connector that onboards itself and one that needs a scheduled call with IT. Both are
capped at what that user can already do, which is usually exactly the semantics a customer wants.

**The jump from `Files.ReadWrite` to `Files.ReadWrite.All` is much larger than the name suggests.** It is not "the
same thing, for more files". In application mode it is tenant-wide read/write over every employee's private OneDrive
and every SharePoint library, granted once and thereafter invisible to the people whose files it covers.

**Mixing defeats the point.** Any scope present in the token is honored, so requesting `Files.SelectedOperations.Selected`
or `Files.ReadWrite` *alongside* `Files.ReadWrite.All` produces a tenant-wide app with a least-privilege label. If you
take a narrow route, the broad scopes come out of the request.

**Product fact — as of 2026-09-20.** Unified.to's OneDrive connector is **delegated only**; there is no app-only
(client-credentials) path of the kind its SharePoint connector offers. Its OAuth2 configuration requests, per object:

- **Reading files:** `Files.Read.All` plus `offline_access` — and nothing else, not even the OIDC scopes.
- **Writing files:** `Files.ReadWrite`, `Files.ReadWrite.All`, `Sites.ReadWrite.All`, plus `offline_access`.
- **Reading or writing directory people and groups** (the connector also carries HR-style objects):
  `Directory.Read.All`, `User.Read`, `User.Read.All` and, for groups, `Group.Read.All` — with `Directory.ReadWrite.All`
  and `User.ReadWrite.All` on the write variants — always with `openid`, `email`, `profile` and `offline_access`.
- **Sign-in only:** `openid`, `User.Read`, `email`.

`offline_access` is requested in every non-login scope set, so refresh tokens are expected. Authorization carries
`prompt=select_account`, the token exchange is form-encoded, and the connector ships Unified.to's own shared client
credentials by default across four clouds (global, US Gov L4, US Gov L5/DoD, China), all through the tenant-agnostic
`common` authority.

**These are the broad `.All` kind that security reviews resist.** A reviewer reading the file-write set sees
`Files.ReadWrite.All` *and* `Sites.ReadWrite.All` — tenant-wide read/write over every user's OneDrive and every
SharePoint site — for a connector whose stated job is files, and whose delegated upload path would be satisfied by
`Files.ReadWrite` alone. The directory scopes (`Directory.Read.All`, `User.Read.All`, `Group.Read.All`) are a second
escalation on top. Expect refusal or escalation at any customer with a security review. **Confirm the current scope
set with the connector's owner before you register anything** — scope lists change and this one is a snapshot.

## 2. The OneDrive / SharePoint boundary

The two products share a storage backend, so the permissions bleed across the line in one direction and not the other.
Get this wrong and you either over-request by an order of magnitude or discover at the customer's site that your
narrow grant cannot see anything.

**`Files.*.All` is tenant-wide across both products.** Microsoft's own wording for the application permissions is
"all files in all site collections" — and in SharePoint Online a user's OneDrive *is* a site collection. So an
app-only `Files.Read.All` grant reaches every employee's private OneDrive and every SharePoint document library, with
one admin consent and no per-site step. That breadth is the reason it gets refused, not a bonus.

**Use `Sites.Selected` and the SharePoint skill when** the target is a named site, a team's document library, or
anything a customer would describe as "our SharePoint": the grant is per site, stamped by a SharePoint Administrator,
and it is the model that passes security review. That skill owns the site-grant mechanics; do not re-derive them here.

**Use the OneDrive model in this file when** the unit of access is *a person's own drive*: delegated `Files.Read` /
`Files.ReadWrite` against `/me/drive`, with each user authorizing for themselves. No admin, no per-site grant, no
tenant-wide reach — and access disappears when the user's own access does.

**Use `Files.SelectedOperations.Selected` when** the unit is a specific file or library folder. The grant is stamped
with `POST /drives/{driveId}/items/{itemId}/permissions`, and two details differ from the site-level grant the
SharePoint skill documents:

- The request body takes **`grantedToV2`**, and the API explicitly rejects `grantedToIdentities` and the deprecated
  `grantedTo` — the site-level body shape does *not* transfer.
- Stamping an item-level grant requires a strong scope on the stamper's side: `Sites.FullControl.All`, or
  `Sites.Selected` / `Lists.SelectedOperations.Selected` already held at **FullControl** or **Owner** role.

Two rules that decide arguments: **scope levels never ladder upward** — `Files.SelectedOperations.Selected` can never
reach a list or a site, while `Sites.*` can be used to grant file-level permissions. And **an item-level grant breaks
SharePoint permission inheritance** on that item, which counts against the tenant's unique-security-scope limits; a
site-level grant does not. If a design wants hundreds of per-file grants, that is a service-limit conversation before
it is a permissions one.

## 3. OneDrive personal vs OneDrive for Business

These are different account systems reached through one API, and the difference lands on the base skill's
supported-account-types dropdown — the one field that is expensive to change later.

| | OneDrive for Business | OneDrive personal (consumer Microsoft account) |
| --- | --- | --- |
| Account | Work/school account in an Entra tenant | Outlook.com / Hotmail / Live / Xbox account |
| `driveType` | `business` | `personal` |
| Audience needed | **Multiple Entra ID tenants** is enough | Must include personal Microsoft accounts — which caps the app at **30 permissions** total (base §3) |
| Application permissions | Yes | **No.** No tenant, no admin, no app-only anything |
| Admin consent | Available, and required for `.All` and Selected scopes | Does not exist |
| Reachable scopes | The whole `Files.*` family | `Files.Read`, `Files.ReadWrite`, `Files.Read.All`, `Files.ReadWrite.All`, `Files.ReadWrite.AppFolder` — **not** `Files.SelectedOperations.Selected`, not the legacy `*.Selected` pair, not `Sites.*` |
| Other users' drives | `/users/{id}/drive`, with admin-level permissions | Only the signed-in user's own drive |

Behavioral differences that surface as bugs, not errors:

- On **personal accounts, `Files.Read` and `Files.ReadWrite` also cover files shared *with* the signed-in user** —
  broader than the same scope on a work account. Documented, and surprising to reviewers.
- **`organization`-scoped sharing links do not exist on consumer OneDrive**; password-protected sharing links exist
  *only* there (§6).
- **Delta's sharing-change headers and the security-event webhooks are SharePoint/OneDrive-for-Business only**, and
  delta's timestamp-as-token form is too (§5).
- Consumer drives carry `description` and `audio` facets and `bundles` (albums) that business drives do not; business
  drives carry `following` that consumer drives do not.

**The practical recommendation**: unless consumer OneDrive is genuinely a product requirement, choose **Multiple Entra
ID tenants** and say so explicitly in the hand-off. Adding personal accounts buys a different customer segment and
costs the 30-permission ceiling, application permissions, and query parameters in redirect URIs. The connector's
endpoints authorizing through `common` does **not** settle this — `common` accepts both audiences, and the
registration's account type is what actually decides which one gets in.

## 4. Addressing: drives and driveItems

Graph exposes `drive` (a container: one per user for OneDrive, one per document library for SharePoint) containing
`driveItem`s (files and folders, distinguished by a `file` or `folder` facet).

| Path | What it addresses |
| --- | --- |
| `/me/drive` | The signed-in user's OneDrive — the delegated connector's entire world |
| `/me/drives` | Every drive available to that user |
| `/users/{user-id}/drive` | Another user's OneDrive (work/school) |
| `/drives/{drive-id}` and `/drives/{drive-id}/items/{item-id}` | A drive, and an item in it, by id |
| `/me/drive/root:/path/to/file` | The same item by path — the colon escapes the relative path |
| `/me/drive/special/{name}` (e.g. `approot`) | A named special folder. **Delegated only** |
| `/sites/{site-id}/drive`, `/sites/{site-id}/drives` | SharePoint libraries — the SharePoint skill's territory |
| `/shares/{share-id}` | An item addressed by a sharing URL or share id |

Four traps:

- **Track items by id, never by path.** Ids persist across renames and moves; paths do not, and delta explicitly
  omits `parentReference.path`, so a path-keyed store silently duplicates every renamed folder's contents.
- **Path addressing needs correct percent-encoding**, per segment. `#` and spaces must be encoded, and you cannot
  encode the whole URL in one call — the segments have different rules. This is the usual cause of a 400 or a
  mysterious 404 on a file whose name contains `#`.
- **A user's OneDrive may not exist yet.** If the drive is not provisioned, `GET /users/{id}/drive` returns **404**.
  With **delegated** authentication and a licensed user, the request provisions the drive automatically; app-only
  does not, and that user stays a 404 until they open OneDrive once themselves. Plan onboarding around it.
- **Do not hammer non-existent OneDrive sites.** Microsoft throttles a client's **IP address** for excessive attempts
  to reach OneDrive site collections that do not exist — which is exactly what enumerating every directory user and
  requesting their drive produces (§7).

## 5. Content: uploads, downloads, and delta

**Uploads split at 250 MB.** `PUT /items/{id}/content` handles files up to **250 MB** in one call. Anything larger
needs an **upload session**, and so does any upload that must survive a dropped connection:

- `POST .../createUploadSession` returns an `uploadUrl` and an `expirationDateTime`. Each accepted fragment extends
  the expiry; if fragments stop arriving, everything uploaded is discarded.
- **The `uploadUrl` is pre-authenticated. Sending an `Authorization` header to it can return `401`** — send the
  bearer token on the `POST` that creates the session, and never on the `PUT`s. This one costs an afternoon.
- Fragments go **sequentially**, each a **multiple of 320 KiB (327,680 bytes)**, each under **60 MiB**. A fragment
  size that is not a multiple of 320 KiB can fail *after* the last byte range is uploaded. Microsoft recommends
  5–10 MiB fragments and resumable transfers for anything over 10 MiB.
- Resume by `GET`ting the `uploadUrl` for `nextExpectedRanges`; cancel with `DELETE`. A `404` on resume means the
  session is gone — start over. Retry 5xx with exponential backoff; do not back off other errors.
- **The app-only permission for creating an upload session is documented as `Sites.ReadWrite.All`, with
  `Files.ReadWrite.All` listed as "Not available."** Delegated needs only `Files.ReadWrite`. If an app-only connector
  must write large files, that is a materially bigger ask than reading them — flag it before promising the feature.
- Replacing the contents of a file carrying a sensitivity label is **not supported with app-only authentication**.

**Downloads.** `@microsoft.graph.downloadUrl` is a pre-authenticated URL that needs no bearer token — convenient, and
a liability. Microsoft documents it as short-lived (**about one hour**), not cacheable, and notes that **removing a
user's permissions might not immediately invalidate it**. Never persist it as if it were a stable file location, and
never hand it to a client you would not hand the file to.

**Delta is how you sync, and the only correct way to enumerate.** Microsoft is explicit: paging `children` is not
guaranteed to return every item if writes happen during enumeration — `delta` is.

- `GET /drives/{id}/root/delta` with no token does the initial crawl; follow `@odata.nextLink` to the end, then keep
  the `@odata.deltaLink` and call it later for changes. `?token=latest` skips the crawl and returns only a cursor.
- A stale or invalidated token returns **`HTTP 410 Gone`** with `resyncChangesApplyDifferences` or
  `resyncChangesUploadDifferences`, plus a `Location` header starting a fresh enumeration. Handle it; disconnected
  connectors hit it routinely.
- The feed shows each item's **latest state, not each change**, and the same item can appear more than once — use the
  last occurrence. Deletions arrive as a `deleted` facet.
- `?token={timestamp}` is supported **only on OneDrive for Business and SharePoint**, and Microsoft says to prefer a
  real `deltaLink` anyway.
- Permission scanning has its own headers — `Prefer: hierarchicalsharing` and `Prefer: deltashowsharingchanges` (the
  latter requiring `deltashowremovedasdeleted, deltatraversepermissiongaps` alongside it). **Microsoft states that
  processing permissions correctly requires `Sites.FullControl.All`** — the single biggest permission in this
  neighbourhood, and not something to request casually for a file-list feature.

**Change notifications instead of polling.** Drives support Graph subscriptions: on **OneDrive for Business** only the
**root folder** (`/drives/{id}/root`, `/users/{id}/drive/root`); on **OneDrive personal** any folder. Maximum
subscription lifetime is **42,300 minutes (under 30 days)** and must be renewed. Notifications say *something changed*,
not what — follow with a delta call. Budget for latency: average under a minute, **maximum six hours**. Acknowledge
with `202` before doing any work, or Graph retries and your connector sees phantom events.

## 6. Sharing links and permissions

- `POST /items/{id}/createLink` creates a sharing link of `type` `view`, `edit` or `embed`, with `scope`
  `anonymous`, `organization` or `users`. **`organization` is OneDrive-for-Business/SharePoint only; `password` is
  OneDrive Personal only.** Anonymous links may be disabled outright by the tenant admin — handle the refusal.
- `retainInheritedPermissions` defaults to `true`. Passing `false` on a first share **removes all existing
  permissions on the item**. Do not set it because an example did.
- `createLink` returns the *existing* link if one of that type already exists for the calling application, so it is
  idempotent per app — not per user.
- `POST /items/{id}/invite` sends invitations; `GET /items/{id}/permissions` lists grants. Delegated needs
  `Files.ReadWrite` (invite/link) or `Files.Read` (list); app-only needs `Files.ReadWrite.All` / `Files.Read.All`.
- Every permission operation is priced at **5 resource units** and sharing APIs have their own cap (§7). Enumerating
  permissions across a drive is the most expensive thing a files connector can do.

## 7. Throttling — what differs from the SharePoint numbers

OneDrive is served by SharePoint Online and shares its budget, so the SharePoint skill's economics apply unchanged:
resource units of **1** (single-item read, delta-with-token, file download), **2** (multi-item query, create/update/
delete/upload) and **5** (any permission operation, including `$expand=permissions`); **1,250–6,250 units per minute**
and **1.2M–6M per 24 hours** per app per tenant, scaling with license count; metering isolated per tenant for
multitenant apps; `Retry-After` honored, `RateLimit` headers unsupported; `ISV|Company|App/Version` decoration; and no
registering extra app IDs to dodge limits. Do not restate or re-derive those — read them there.

What a OneDrive connector hits that a SharePoint one usually does not:

- **Per-user limits, which a delegated connector shares with the human.** Roughly **3,000 requests per 5 minutes**,
  **50 GB ingress per hour** and **100 GB egress per hour** *per user*, aggregated across all apps. A user running
  the OneDrive sync client while your connector crawls their drive can throttle both.
- **Per-app-per-tenant bandwidth caps of 400 GB ingress and 400 GB egress per hour**, license-independent. A backup
  or migration-shaped connector meets these before it meets the resource-unit ceiling.
- **Specific sharing APIs: 300 calls per 5 minutes per app per tenant.** Sharing-link creation is not file I/O and is
  not budgeted like it.
- **Tenant-wide resource units of 18,750–93,750 per 5 minutes**, shared across every app — your connector can be
  throttled by someone else's.
- **IP-level throttling for repeatedly requesting OneDrive site collections that do not exist** (§4).
- Microsoft names "using SharePoint and OneDrive as an intermediary service between Microsoft 365 and another
  repository" as an **unsupported use case** that may be throttled. If that is the connector's actual shape, say so
  to the customer rather than tuning retries.

## 8. Verify the OneDrive-specific parts

Run the base skill's end-to-end check first (a *different* tenant, a non-admin user, `refresh_token` present, token
claims decoded). Then:

1. `GET /me/drive` and confirm `driveType` matches the account kind you intended (`business` vs `personal`).
2. List one folder's children **and** read one file's content. Reading metadata proves less than it looks.
3. Run `delta` with no token, follow to the `deltaLink`, change one file, and call the `deltaLink` again. A connector
   that has never exercised a `deltaLink` has not been tested.
4. If uploads are in scope, upload one file over 250 MB through an upload session, with a deliberately interrupted
   fragment, and resume it.
5. If the design targets other users' drives, test a user who has **never opened OneDrive** — that is the 404 case.
6. If `Files.SelectedOperations.Selected` is the model, confirm access is **denied before** the item grant and
   allowed after. If it works before, your token carries something broader (§1).
7. If personal Microsoft accounts are in scope, test one — permission validity, sharing-link options and delta
   behavior all differ (§3).

| Symptom | Cause |
| --- | --- |
| `404` on `/users/{id}/drive` for some users only | Their OneDrive was never provisioned; app-only will not provision it (§4) |
| Auth succeeds, every file call is `403 accessDenied` | `Files.SelectedOperations.Selected` consented but no item grant stamped — or the grant is on a different item (§2) |
| `401` on the upload `PUT`s, `200` on the session create | `Authorization` header sent to the pre-authenticated `uploadUrl` (§5) |
| Large upload fails *after* the last fragment | Fragment size not a multiple of 320 KiB, or a name conflict at commit (§5) |
| Delta returns `410 Gone` | Token stale/invalidated — follow the `Location` header and re-enumerate (§5) |
| Sync duplicates a folder's contents after a rename | Items tracked by path instead of id (§4) |
| Stored download URLs stop working after ~an hour | `@microsoft.graph.downloadUrl` is short-lived and uncacheable (§5) |
| `organization`-scoped sharing link rejected | Consumer OneDrive has no organization scope (§3, §6) |
| Item loses all its other permissions on first share | `retainInheritedPermissions: false` (§6) |
| `429` on an IP that has never been busy | Repeated requests for OneDrive sites that do not exist (§4, §7) |
| App-only large-file upload refused where reads work | App-only upload sessions are documented against `Sites.ReadWrite.All` (§5) |
| Consent screen shows far more than "files" | `Sites.ReadWrite.All` / `Directory.Read.All` riding along with the file scopes (§1) |

## Hand off — the OneDrive additions

The base skill's hand-off list applies. Add to the closing summary: which access model was chosen (delegated
per-user, app folder, per-item Selected, or tenant-wide `.All`) **and the reason**; whether consumer Microsoft
accounts are in scope and therefore which supported-account-type was set; for item-level grants, which items were
granted, with which role, and who stamped them; and whether uploads over 250 MB are in scope, since that changes the
app-only permission requirement.

## Stop and ask

On top of the base skill's conditions, hand back to a human when:

- Tenant-wide `Files.Read.All` / `Files.ReadWrite.All` in **application** mode is being proposed where a delegated
  per-user token would do. That is a security decision with a named blast radius: every employee's private OneDrive
  (§1, §2).
- The target is really SharePoint sites or team libraries — that is `Sites.Selected` and the SharePoint skill, not
  this one (§2).
- Consumer OneDrive is being added to a connector that already needs more than 30 permissions, or that relies on
  application permissions (§3).
- A design depends on `Files.Read.Selected` / `Files.ReadWrite.Selected` — those are the legacy file-handler scopes,
  not per-item access; the plan needs rewriting (Platform state).
- Permission scanning is in scope and nobody has weighed `Sites.FullControl.All` (§5).
- Hundreds of per-item grants are planned without anyone checking unique-security-scope limits (§2).
- The connector's shape is "move data between Microsoft 365 and another repository at volume" — Microsoft calls that
  an unsupported use case (§7).
- Microsoft's own pages disagree with what you observe (the app-only drive tables are a known instance) — report the
  observation, do not pick a page to believe.

## References

The base skill carries the shared Entra references (permissions reference, scopes, consent, secrets, AADSTS codes),
and the SharePoint skill carries the site-grant and SharePoint-throttling references. These are the OneDrive- and
Graph-files-specific ones; verified 2026-09-20, every link returned HTTP 200.

- Working with files in Microsoft Graph (drive/driveItem overview, addressing) — https://learn.microsoft.com/en-us/graph/api/resources/onedrive?view=graph-rest-1.0
- Addressing driveItems (id vs path, percent-encoding) — https://learn.microsoft.com/en-us/graph/onedrive-addressing-driveitems
- drive resource (`driveType`, personal vs business differences) — https://learn.microsoft.com/en-us/graph/api/resources/drive?view=graph-rest-1.0
- driveItem resource (facets, `@microsoft.graph.downloadUrl` lifetime) — https://learn.microsoft.com/en-us/graph/api/resources/driveitem?view=graph-rest-1.0
- Get drive (provisioning behavior, 404) — https://learn.microsoft.com/en-us/graph/api/drive-get?view=graph-rest-1.0
- Get a special folder (`approot`; delegated only) — https://learn.microsoft.com/en-us/graph/api/drive-get-specialfolder?view=graph-rest-1.0
- driveItem: delta (sync, resync errors, permission-scanning headers) — https://learn.microsoft.com/en-us/graph/api/driveitem-delta?view=graph-rest-1.0
- Upload or replace file contents (250 MB limit) — https://learn.microsoft.com/en-us/graph/api/driveitem-put-content?view=graph-rest-1.0
- driveItem: createUploadSession (fragments, resume, app-only permission) — https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession?view=graph-rest-1.0
- uploadSession resource — https://learn.microsoft.com/en-us/graph/api/resources/uploadsession?view=graph-rest-1.0
- Upload large files with the Microsoft Graph SDKs — https://learn.microsoft.com/en-us/graph/sdks/large-file-upload
- Download driveItem content — https://learn.microsoft.com/en-us/graph/api/driveitem-get-content?view=graph-rest-1.0
- driveItem: createLink (link types, scopes, `retainInheritedPermissions`) — https://learn.microsoft.com/en-us/graph/api/driveitem-createlink?view=graph-rest-1.0
- driveItem: invite — https://learn.microsoft.com/en-us/graph/api/driveitem-invite?view=graph-rest-1.0
- Create a permission on a driveItem (`grantedToV2`) — https://learn.microsoft.com/en-us/graph/api/driveitem-post-permissions?view=graph-rest-1.0
- List driveItem permissions — https://learn.microsoft.com/en-us/graph/api/driveitem-list-permissions?view=graph-rest-1.0
- Access a shared item by sharing URL — https://learn.microsoft.com/en-us/graph/api/shares-get?view=graph-rest-1.0
- Selected permissions in OneDrive and SharePoint (file-level grants, inheritance) — https://learn.microsoft.com/en-us/graph/permissions-selected-overview
- Best practices for discovering files and detecting changes at scale — https://learn.microsoft.com/en-us/onedrive/developer/rest-api/concepts/scan-guidance?view=odsp-graph-online
- Change notifications overview (drive subscriptions, lifetime, latency) — https://learn.microsoft.com/en-us/graph/change-notifications-overview
- OneDrive developer REST API landing page — https://learn.microsoft.com/en-us/onedrive/developer/rest-api/?view=odsp-graph-online
