Search code examples
sharepointmicrosoft-graph-apisharepoint-onlineazure-ad-graph-apisharepoint-api

How do I authorize a Python script to upload to SharePoint Online?


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.


Solution

  • 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:

    enter image description here

    I have one SharePoint site named sritestsite having one document library with sri folder like below:

    enter image description here

    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:

    enter image description here

    To confirm that, I checked the same in SharePoint portal where test.txt file uploaded successfully like below:

    enter image description here

    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:

    enter image description here

    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:

    enter image description here