Introduction
You’re now ready to build SharePoint file access through your Azure Function or MCP tool. This guide will walk you through authenticating with Client ID and Secret, while ensuring your App Registration has scoped, limited access to only the required SharePoint site
- The Challenge: Why traditional authentication doesn’t work for service-to-service scenarios
- The Solution: Setting up Azure AD app registration with client credentials
- The Implementation: Running PowerShell scripts to grant site permissions
- The Cleanup: Revoking access when you’re done
Prerequisites: Azure subscription, SharePoint site, admin permissions
The Problem: Service-to-Service Authentication
You’ve built an Azure Function or Model Context Protocol (MCP) tool that needs to read/write files to SharePoint. You try the obvious approaches:
# ❌ This won't work for automated services
ctx = ClientContext(site_url).with_user_credentials(username, password)
Why this fails:
- No interactive login: Azure Functions run unattended—no one’s there to type credentials
- Security risk: Storing user passwords in environment variables is a compliance nightmare
- MFA breaks it: Modern organizations require multi-factor authentication
- Token expiration: User sessions expire, causing random failures
You need application-level authentication that works without human intervention.
The Solution: Azure AD Application with Client Credentials
Instead of using a user account, we’ll create an Azure AD application identity with its own credentials.

Key Components:
- Client ID: Public identifier for your application (like a username)
- Client Secret: Password for your application (never commit to Git!)
- Tenant ID: Your organization’s Azure AD identifier
- Site Permissions: Explicitly granted access to specific SharePoint sites
Step-by-Step Implementation
Phase 1: Create Azure AD Application (5 minutes)
1. Navigate to Azure Portal
Azure Portal → Azure Active Directory → App registrations → + New registration
2. Register Your Application
| Field | Value |
|---|---|
| Name | SharePoint Integration App |
| Supported account types | Single tenant |
| Redirect URI | Leave blank |
Click Register and save these values:
Application (client) ID: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
Directory (tenant) ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
3. Configure API Permissions
Add these Microsoft Graph permissions:
Application Permissions (for service-to-service):
- ✅
Sites.Selected– Access specific sites (recommended)
Delegated Permissions (for user context):
- ✅
email– User email address - ✅
offline_access– Refresh tokens - ✅
openid– Sign-in capability - ✅
profile– Basic user info
4. Grant Admin Consent
⚠️ Critical: Click “Grant admin consent for [Your Organization]”
Without this, your app won’t have actual permissions—just requests for them.

5. Create Client Secret
Certificates & secrets → + New client secret
Description: "SharePoint Access Key"
Expires: 180 days (recommended for production)
🔐 SAVE THE SECRET VALUE IMMEDIATELY – you can’t retrieve it later!

Client Secret: abc~xyz789EXAMPLE_DoNotCommitThisToGit...
Phase 2: Grant Site-Level Permissions
Now that your Azure AD app exists, you need to explicitly grant it access to your SharePoint site.
Why this step?Even with Sites.Selected permission, Azure AD doesn’t know which sites to allow. This is the “allow list” step.
1. Download PowerShell Scripts
Clone this repository or download the scripts:
git clone https://github.com/nashtech-garage/SharePoint-permission.git
2. Edit Configuration
Open grant-access.bat and update:
SET TenantId=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
SET SiteUrl=https://contoso.sharepoint.com/sites/your-site
SET AppId=yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
SET Permission=write
3. Run Grant Script
.\grant-access.bat
What happens:
- PowerShell opens a browser for admin authentication
- You sign in with your admin account
- Script resolves the SharePoint site ID
- Grants the specified permission to your app
- Confirms success
Expected output:
========================================
SharePoint Site Permission Grant Tool
========================================
Tenant ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Site URL: https://contoso.sharepoint.com/sites/your-site
App ID: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
Permission: write
*** IMPORTANT NOTE ***
This script grants SITE-LEVEL permissions, which apply to ALL libraries in the site.
========================================
Connecting to Microsoft Graph...
Successfully connected to tenant.
Resolving SharePoint site...
Site Name: Your Site
Site ID: contoso.sharepoint.com,abc123,def456
Granting site-level permission...
SUCCESS: Granted write permission to site
This permission applies to ALL libraries in the site
========================================
Permission grant process completed!
========================================
4. Verify Permissions
Run the check script to confirm:
.\check-access.bat
You should see your app listed with the granted roles.
Phase 3: Use in Your Application
Azure Function Example (Python):
import os
from office365.sharepoint.client_context import ClientContext
from office365.runtime.auth.client_credential import ClientCredential
# Load from environment variables or Azure Key Vault
tenant_id = os.getenv('AZURE_TENANT_ID')
client_id = os.getenv('AZURE_CLIENT_ID')
client_secret = os.getenv('AZURE_CLIENT_SECRET')
site_url = os.getenv('SHAREPOINT_SITE_URL')
# Authenticate using client credentials
credentials = ClientCredential(client_id, client_secret)
ctx = ClientContext(site_url).with_credentials(credentials)
# Access SharePoint
web = ctx.web.get().execute_query()
print(f"✅ Connected to: {web.title}")
# Upload a file
folder = ctx.web.get_folder_by_server_relative_url("/sites/your-site/Shared Documents")
with open("report.pdf", "rb") as f:
folder.upload_file("report.pdf", f.read()).execute_query()
print("✅ File uploaded successfully")
MCP Tool Example (Configuration):
{
"mcpServers": {
"sharepoint": {
"command": "python",
"args": ["-m", "sharepoint_mcp"],
"env": {
"AZURE_TENANT_ID": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"AZURE_CLIENT_ID": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"AZURE_CLIENT_SECRET": "abc~xyz789...",
"SHAREPOINT_SITE_URL": "https://contoso.sharepoint.com/sites/your-site"
}
}
}
}
Azure Function Configuration (App Settings):
AZURE_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
AZURE_CLIENT_ID=yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
AZURE_CLIENT_SECRET=@Microsoft.KeyVault(SecretUri=https://your-vault.vault.azure.net/secrets/SharePointSecret/)
SHAREPOINT_SITE_URL=https://contoso.sharepoint.com/sites/your-site
💡 Pro tip: Use Azure Key Vault for secrets in production—never hardcode them!
Important Limitations & Workarounds
⚠️ Site-Level vs Library-Level Permissions
The Limitation:Microsoft Graph API only supports site-level permissions for applications. You cannot grant access to specific libraries.
What this means:
- Permission applies to ALL libraries in the site
- No way to restrict app to “Documents” library only
- Graph API doesn’t expose library-granular controls
The Workaround:Implement access control in your application code:
# config.py
ALLOWED_LIBRARIES = ["Documents", "Reports", "Assets"]
# sharepoint_service.py
def validate_library_access(library_name: str):
if library_name not in ALLOWED_LIBRARIES:
raise PermissionError(f"Access denied to library: {library_name}")
# Proceed with operation
Alternative Architecture:
- Use separate SharePoint sites for strict isolation
- Grant app access only to the sites it needs
- One app per site if maximum security is required
Troubleshooting Common Issues
🔴 Error: “Application does not have permission to access this site”
Cause: Site permission not granted via scripts.
Fix:
# Re-run grant script
.\grant-library-access.ps1 -TenantId "..." -SiteUrl "..." -AppId "..." -Permission "write"
🔴 Error: “Client secret has expired”
Cause: Secrets expire after the configured period (180 days, 1 year, etc.).
Fix:
- Azure Portal → App registrations → Your app → Certificates & secrets
- Delete expired secret
- Create new secret
- Update environment variables/Key Vault
- Restart your application
Prevention:Set calendar reminders 30 days before expiration.
🔴 Error: “Insufficient privileges to complete the operation”
Cause: Admin consent not granted in Azure Portal.
Fix:
- Azure Portal → App registrations → Your app → API permissions
- Click “Grant admin consent for [Your Organization]”
- Verify green checkmarks appear
- Wait 5 minutes for propagation
- Retry
🔴 Error: “Site not found” in PowerShell script
Cause: Incorrect Site URL format.
Fix:
✅ Correct: https://contoso.sharepoint.com/sites/demo
❌ Wrong: https://contoso.sharepoint.com/sites/demo/
❌ Wrong: https://contoso.sharepoint.com/sites/demo/Shared%20Documents
Cleanup: Revoking Access When Done
When your project ends or you no longer need SharePoint access:
Option 1: Revoke Site Permissions (Keep App)
Use this if you want to keep the Azure AD app but remove SharePoint access:
.\revoke-access.bat
What happens:
- Script finds all permissions for your app
- Shows what will be deleted
- Asks for “YES” confirmation
- Removes site-level permissions via Graph API
Result: App still exists in Azure AD but can’t access SharePoint.
Option 2: Delete Azure AD Application (Complete Cleanup)
Use this for complete removal:
Delete via Azure Portal:
Azure Portal → App registrations → Your app → Delete → Confirm
Result: App and all its permissions are permanently deleted.
Real-World Use Cases
✅ Document Processing Pipeline
Scenario: MCP tool monitors SharePoint folder, extracts text from PDFs, indexes in Azure AI Search.
Benefits:
- Automatic content indexing
- Enhanced search capabilities
- RAG-powered chatbots
- Compliance document analysis
✅ Multi-Site Data Aggregation
Scenario: Azure Function accesses SharePoint sites, consolidates data into central dashboard.
Benefits:
- Single view of distributed data
- Cross-site analytics
- Centralized reporting
- Reduced manual data gathering
Key Takeaways
Client ID + Secret authentication enables secure, automated access to SharePoint without user login
Permissions can be scoped to a single SharePoint site, ensuring least-privilege access
Setup takes ~15–20 minutes to register the Azure AD app and configure access
More secure than user passwords, suitable for production workloads
Fully automated workflows—no human involvement required after setup
Easily revocable by disabling secret or removing access when no longer needed
Next Steps
- Implement library-level access control in your application
- Set up Azure Key Vault for secret storage
- Enable Application Insights for monitoring
- Configure automated secret rotation
Additional Resources
- https://learn.microsoft.com/en-us/graph/api/site-post-permissions
- https://techcommunity.microsoft.com/blog/spblog/develop-applications-that-use-sites-selected-permissions-for-spo-sites-/3790476
- https://learn.microsoft.com/en-us/graph/api/site-post-permissions?view=graph-rest-1.0&tabs=http