I need to use a Python script to upload files to a SharePoint Online site using a client credentials auth flow. I am a tenant administrator and have tried granting app-only access (as described here), as well as through Azure AD, in both cases giving full site permissions. In the case of Azure AD, I've tried authorizing through the MS Graph API, as well as the SharePoint API. In both cases, I can authenticate but cannot authorize for access to the SharePoint site.
I am able to generate a Bearer access token showing Sites.FullControl.All access. However, I either get Unsupported app only token
(in the case of using client_id/secret from Azure AD app registration) or ID3035: The request was not valid or is malformed
(in the case of in the case of using client_id/secret from app-only registration through the SharePoint admin interface).
I've also attempted to authorize via the Office365-Rest-Python-Client
, which authorizes but returns a 401 when attempting to access any site resources.
I've found some evidence in the docs that obtaining a refresh token maybe required, which may require a self-signed cert, but I've gone down so many rabbit holes that I thought I'd reach out here for any potential insight.
Bottom line, I just need to run a script that uploads a file daily to a SharePoint site without any user interaction.
I tried to reproduce the same in my environment and got below results:
I registered one Azure AD application and granted API permissions
as below:
I have one SharePoint site named sritestsite
having one document library with sri
folder like below:
I used below Python script to upload local file to SharePoint document library folder via Graph API without user interaction like this:
import os
import requests
# Azure AD app registration credentials
client_id = '376f340a-7b96-40c6-89fb-xxxxxxxxx'
client_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxx'
tenant_id = '3f5c7a77-062d-426c-8582-1xxxxxxxxxxx'
# SharePoint Online site URL and library name
site_id = '6d4d4ae7-be11-47d0-a9ad-xxxxxxxxxxx'
library_name = 'sridoclib'
drive_id = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
# Authenticate and get an access token
auth_url = f'https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token'
data = {
'grant_type': 'client_credentials',
'client_id': client_id,
'client_secret': client_secret,
'scope': 'https://graph.microsoft.com/.default'
}
response = requests.post(auth_url, data=data)
access_token = response.json()['access_token']
# Upload a file to the SharePoint document library using the Microsoft Graph API
file_path = 'C:/Users/sridevi/Desktop/test.txt' #local file path
file_name = 'test.txt'
folder_name = 'sri'
upload_url = f'https://graph.microsoft.com/v1.0/sites/{site_id}/drives/{drive_id}/items/root:/{folder_name}/{file_name}:/content'
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/octet-stream',
'Content-Length': str(os.path.getsize(file_path))
}
with open(file_path, 'rb') as file:
response = requests.put(upload_url, headers=headers, data=file)
print(response.json())
Response:
To confirm that, I checked the same in SharePoint portal where test.txt
file uploaded successfully like below:
You can get site_id
of your site using below Graph API query:
GET https://graph.microsoft.com/v1.0/sites/root:/sites/<site_name>/
Response:
Using the above site_id, you can get drive_id
like below:
GET https://graph.microsoft.com/v1.0/sites/6d4d4ae7-be11-47d0-a9ad-xxxxxxxxx/drives/
Response: