Upload file to MS SharePoint using the Python OneDrive SDK

Can I upload a file to the Microsoft SharePoint General Documents Library using the Python OneDrive SDK ?

This documentation says that it should be (in the first sentence), but I cannot do this work.

I can authenticate (using Azure AD) and upload it to the OneDrive folder, but when I try to upload it to the SharePoint folder, I keep getting this error

Type Exception Microsoft.IdentityModel.Tokens. AudienceUriValidationFailedException "was selected.

The code I use returns an object with an error:

(...authentication...) client = onedrivesdk.OneDriveClient('https://{tenant}.sharepoint.com/{site}/_api/v2.0/', auth, http) client.item(path='/drive/special/documents').children['test.xlsx'].upload('test.xlsx') 

where i want to download on the internet

I can successfully download to https://{tenant}-my.sharepoint.com/_api/v2.0/ (note the -my "after {tenant} ) with the following code:

 client = onedrivesdk.OneDriveClient('https://{tenant}-my.sharepoint.com/_api/v2.0/', auth, http) returned_item = client.item(drive='me', id='root').children['test.xlsx'].upload('test.xlsx') 

How can I upload the same file to a SharePoint site?

(Answers to similar questions ( 1 , 2 , 3 , 4 ) when stack overflows are either too vague or suggest using a different API. My question is whether the OneDrive Python SDK can be used, and if so, how to do it.)


Refresh . Here is my complete code and conclusion. (Sensitive input has been replaced by similarly formatted gibberish.)

 import re import onedrivesdk from onedrivesdk.helpers.resource_discovery import ResourceDiscoveryRequest # our domain (not the original) redirect_uri = 'https://example.ourdomain.net/' # our client id (not the original) client_id = "a1234567-1ab2-1234-a123-ab1234abc123" # our client secret (not the original) client_secret = 'ABCaDEFGbHcd0e1I2fghJijkL3mn4M5NO67P8Qopq+r=' resource = 'https://api.office.com/discovery/' auth_server_url = 'https://login.microsoftonline.com/common/oauth2/authorize' auth_token_url = 'https://login.microsoftonline.com/common/oauth2/token' http = onedrivesdk.HttpProvider() auth = onedrivesdk.AuthProvider(http_provider=http, client_id=client_id, auth_server_url=auth_server_url, auth_token_url=auth_token_url) should_authenticate_via_browser = False try: # Look for a saved session. If not found, we'll have to # authenticate by opening the browser. auth.load_session() auth.refresh_token() except FileNotFoundError as e: should_authenticate_via_browser = True pass if should_authenticate_via_browser: auth_url = auth.get_auth_url(redirect_uri) code = '' while not re.match(r'[a-zA-Z0-9_-]+', code): # Ask for the code print('Paste this URL into your browser, approve the app\ access.') print('Copy the resulting URL and paste it below.') print(auth_url) code = input('Paste code here: ') # Parse code from URL if necessary if re.match(r'.*?code=([a-zA-Z0-9_-]+).*', code): code = re.sub(r'.*?code=([a-zA-Z0-9_-]*).*', r'\1', code) auth.authenticate(code, redirect_uri, client_secret, resource=resource) # If you have access to more than one service, you'll need to decide # which ServiceInfo to use instead of just using the first one, as below. service_info = ResourceDiscoveryRequest().get_service_info(auth.access_token)[0] auth.redeem_refresh_token(service_info.service_resource_id) auth.save_session() # Save session into a local file. # Doesn't work client = onedrivesdk.OneDriveClient( 'https://{tenant}.sharepoint.com/sites/{site}/_api/v2.0/', auth, http) returned_item = client.item(path='/drive/special/documents') .children['test.xlsx'] .upload('test.xlsx') print(returned_item._prop_dict['error_description']) # Works, uploads to OneDrive instead of SharePoint site client2 = onedrivesdk.OneDriveClient( 'https://{tenant}-my.sharepoint.com/_api/v2.0/', auth, http) returned_item2 = client2.item(drive='me', id='root') .children['test.xlsx'] .upload('test.xlsx') print(returned_item2.web_url) 

Output:

 Exception of type 'Microsoft.IdentityModel.Tokens.AudienceUriValidationFailedException' was thrown. https://{tenant}-my.sharepoint.com/personal/user_domain_net/_layouts/15/WopiFrame.aspx?sourcedoc=%1ABCDE2345-67F8-9012-3G45-6H78IJKL9M01%2N&file=test.xlsx&action=default 
+6
source share
1 answer

Finally, I found a solution using (SO user) sytech.

The answer to my original question is that using the original Python OneDrive SDK , it is not possible to upload the file to the Shared Documents folder of a SharePoint Online site (at the time of writing this): when the resource discovery service requests the SDK, it deletes all the services whose service_api_version not v2.0 . However, I get the SharePoint service with v1.0 , so it was deleted, although it could be accessed using the v2.0 API.

However , by extending the ResourceDiscoveryRequest class (in the OneDrive SDK), we can create a workaround for this. I was able to download the file as follows:

 import json import re import onedrivesdk import requests from onedrivesdk.helpers.resource_discovery import ResourceDiscoveryRequest, \ ServiceInfo # our domain (not the original) redirect_uri = 'https://example.ourdomain.net/' # our client id (not the original) client_id = "a1234567-1ab2-1234-a123-ab1234abc123" # our client secret (not the original) client_secret = 'ABCaDEFGbHcd0e1I2fghJijkL3mn4M5NO67P8Qopq+r=' resource = 'https://api.office.com/discovery/' auth_server_url = 'https://login.microsoftonline.com/common/oauth2/authorize' auth_token_url = 'https://login.microsoftonline.com/common/oauth2/token' # our sharepoint URL (not the original) sharepoint_base_url = 'https://{tenant}.sharepoint.com/' # our site URL (not the original) sharepoint_site_url = sharepoint_base_url + 'sites/{site}' file_to_upload = 'C:/test.xlsx' target_filename = 'test.xlsx' class AnyVersionResourceDiscoveryRequest(ResourceDiscoveryRequest): def get_all_service_info(self, access_token, sharepoint_base_url): headers = {'Authorization': 'Bearer ' + access_token} response = json.loads(requests.get(self._discovery_service_url, headers=headers).text) service_info_list = [ServiceInfo(x) for x in response['value']] # Get all services, not just the ones with service_api_version 'v2.0' # Filter only on service_resource_id sharepoint_services = \ [si for si in service_info_list if si.service_resource_id == sharepoint_base_url] return sharepoint_services http = onedrivesdk.HttpProvider() auth = onedrivesdk.AuthProvider(http_provider=http, client_id=client_id, auth_server_url=auth_server_url, auth_token_url=auth_token_url) should_authenticate_via_browser = False try: # Look for a saved session. If not found, we'll have to # authenticate by opening the browser. auth.load_session() auth.refresh_token() except FileNotFoundError as e: should_authenticate_via_browser = True pass if should_authenticate_via_browser: auth_url = auth.get_auth_url(redirect_uri) code = '' while not re.match(r'[a-zA-Z0-9_-]+', code): # Ask for the code print('Paste this URL into your browser, approve the app\ access.') print('Copy the resulting URL and paste it below.') print(auth_url) code = input('Paste code here: ') # Parse code from URL if necessary if re.match(r'.*?code=([a-zA-Z0-9_-]+).*', code): code = re.sub(r'.*?code=([a-zA-Z0-9_-]*).*', r'\1', code) auth.authenticate(code, redirect_uri, client_secret, resource=resource) service_info = AnyVersionResourceDiscoveryRequest().\ get_all_service_info(auth.access_token, sharepoint_base_url)[0] auth.redeem_refresh_token(service_info.service_resource_id) auth.save_session() client = onedrivesdk.OneDriveClient(sharepoint_site_url + '/_api/v2.0/', auth, http) # Get the drive ID of the Documents folder. documents_drive_id = [x['id'] for x in client.drives.get()._prop_list if x['name'] == 'Documents'][0] items = client.item(drive=documents_drive_id, id='root') # Upload file uploaded_file_info = items.children[target_filename].upload(file_to_upload) 

Authentication for another service gives you a different token.

+3
source

All Articles