Skip to content
Back to skills

Sharepoint

CSecurity

Read and write SharePoint sites, document libraries, files and lists through Microsoft Graph. Use when the user asks about SharePoint sites, team documents, shared files, or SharePoint lists.

  • 71 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 3, 2026
developmentshell

Works with

  • cli

Security analysis

C63/100
  • criticalAccesses sensitive system or user directories
  • criticalSends environment variables or credentials to an external URL

Pro shows the line behind each finding and how to fix it

Scanned October 7, 2026

npx -y skills add intentic/intentic --skill sharepoint --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sharepoint?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sharepoint
[![Security: C — Skills Directory](https://www.skillsdirectory.com/api/skills/intentic-sharepoint/badge)](https://www.skillsdirectory.com/skills/intentic-sharepoint)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: sharepoint
description: Read and write SharePoint sites, document libraries, files and lists through Microsoft Graph. Use when the user asks about SharePoint sites, team documents, shared files, or SharePoint lists.
---

# SharePoint (connected)

App-only access through Microsoft Graph. Credentials in `$SHAREPOINT_TENANT_ID`, `$SHAREPOINT_CLIENT_ID` and
`$SHAREPOINT_CLIENT_SECRET`; `$SHAREPOINT_HOSTNAME` may hold the tenant's host (`contoso.sharepoint.com`).
There is no user behind this token: it is the app itself, so "my files" / OneDrive personal drives are out of
reach and `/me` always fails. Get an hour-long token, then call Graph with it:

```sh
sp_token() { curl -s -X POST "$SHAREPOINT_LOGIN_URL/$SHAREPOINT_TENANT_ID/oauth2/v2.0/token" \
  -d "client_id=$SHAREPOINT_CLIENT_ID" -d "client_secret=$SHAREPOINT_CLIENT_SECRET" \
  -d "scope=https://graph.microsoft.com/.default" -d "grant_type=client_credentials" | jq -r '.access_token'; }
SP=$(sp_token)   # re-run when calls start answering 401 (the token lasts ~1 hour)
sp() { local m="$1" p="$2"; shift 2; curl -s -X "$m" -H "Authorization: Bearer $SP" \
  -H "Content-Type: application/json" "https://graph.microsoft.com/v1.0/$p" "$@"; }
```

If `sp_token` answers no token, print the body: it comes back as `{error, error_description}` and the
description spells the cause out in words, `AADSTS…` code and all: quote it rather than guessing from the short
`error` alone. A 403 on a call that looks right is almost always the
missing piece from setup: admin consent was never granted, or the app has `Sites.Selected` and nobody granted it
this site. Say that rather than "the site does not exist".

- Find sites: `sp GET "sites?search=<TERM>" | jq -c '.value[] | {id, name, webUrl}'` (root site: `sp GET sites/root`)
- A site by URL path: `sp GET "sites/$SHAREPOINT_HOSTNAME:/sites/<SITE>" | jq '{id, displayName, webUrl}'`
- Subsites: `sp GET "sites/<SITE_ID>/sites" | jq -c '.value[] | {id, name, webUrl}'`
- Document libraries: `sp GET "sites/<SITE_ID>/drives" | jq -c '.value[] | {id, name, webUrl}'`, the default one is `sp GET "sites/<SITE_ID>/drive"`
- Browse a library: `sp GET "drives/<DRIVE_ID>/root/children" | jq -c '.value[] | {id, name, size, folder: (.folder != null), lastModifiedDateTime}'` · a subfolder: `sp GET "drives/<DRIVE_ID>/root:/<FOLDER PATH>:/children"`
- Find files in a library: `sp GET "drives/<DRIVE_ID>/root/search(q='<TERM>')" | jq -c '.value[] | {id, name, webUrl}'`
- Download a file: `curl -sL -H "Authorization: Bearer $SP" "https://graph.microsoft.com/v1.0/drives/<DRIVE_ID>/items/<ITEM_ID>/content" -o <FILE>`, `-L`, because Graph redirects to storage
- Upload a file (under 4 MB): `curl -s -X PUT -H "Authorization: Bearer $SP" --data-binary @<FILE> "https://graph.microsoft.com/v1.0/drives/<DRIVE_ID>/root:/<FOLDER>/<NAME>:/content" | jq '{id, name, webUrl}'`, larger files need an upload session (`.../createUploadSession`)
- Create a folder: `sp POST "drives/<DRIVE_ID>/root/children" -d '{"name":"<NAME>","folder":{},"@microsoft.graph.conflictBehavior":"rename"}'`
- Lists on a site: `sp GET "sites/<SITE_ID>/lists" | jq -c '.value[] | {id, name, template: .list.template}'`, `documentLibrary` templates are the libraries above, seen from the list side
- A list's columns: `sp GET "sites/<SITE_ID>/lists/<LIST_ID>/columns" | jq -c '.value[] | {name, displayName, readOnly}'`
- List rows: `sp GET "sites/<SITE_ID>/lists/<LIST_ID>/items?expand=fields&\$top=100" | jq -c '.value[] | {id, fields}'`, without `expand=fields` the rows come back empty of content
- Add a row: `sp POST "sites/<SITE_ID>/lists/<LIST_ID>/items" -d '{"fields":{"Title":"...","Status":"Open"}}'`, keys are the columns' internal `name`s, not their display names
- Update / delete a row: `sp PATCH "sites/<SITE_ID>/lists/<LIST_ID>/items/<ITEM_ID>/fields" -d '{"Status":"Done"}'` · `sp DELETE "sites/<SITE_ID>/lists/<LIST_ID>/items/<ITEM_ID>"`

Notes: a site id is a comma-joined triple (`contoso.sharepoint.com,<guid>,<guid>`), ugly but ordinary, pass it
whole. Escape `$` in Graph's own query params inside double quotes (`\$top`, `\$select`, `\$filter`) or the shell
eats them. Page with `.["@odata.nextLink"]`, which is a full URL: call it directly with the bearer header.
Errors arrive as `{error: {code, message}}`; quote the `message`. Writes land as the app, not as a person, and
show in version history as such: say what you are about to change before changing shared documents.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.