Skip to content

Instantly share code, notes, and snippets.

@keathmilligan
Created March 23, 2020 16:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save keathmilligan/62a314e04880962427f031c10a184831 to your computer and use it in GitHub Desktop.
Save keathmilligan/62a314e04880962427f031c10a184831 to your computer and use it in GitHub Desktop.
Get info about and download a file from a SharePoint site with Microsoft Graph and MSAL
import requests
import msal
import atexit
import os.path
import urllib.parse
TENANT_ID = '<your tenant id>'
CLIENT_ID = '<your application id>'
SHAREPOINT_HOST_NAME = 'yourcompany.sharepoint.com'
SITE_NAME = '<your site name>'
AUTHORITY = 'https://login.microsoftonline.com/' + TENANT_ID
ENDPOINT = 'https://graph.microsoft.com/v1.0'
SCOPES = [
'Files.ReadWrite.All',
'Sites.ReadWrite.All',
'User.Read',
'User.ReadBasic.All'
]
cache = msal.SerializableTokenCache()
if os.path.exists('token_cache.bin'):
cache.deserialize(open('token_cache.bin', 'r').read())
atexit.register(lambda: open('token_cache.bin', 'w').write(cache.serialize()) if cache.has_state_changed else None)
app = msal.PublicClientApplication(CLIENT_ID, authority=AUTHORITY, token_cache=cache)
accounts = app.get_accounts()
result = None
if len(accounts) > 0:
result = app.acquire_token_silent(SCOPES, account=accounts[0])
if result is None:
flow = app.initiate_device_flow(scopes=SCOPES)
if 'user_code' not in flow:
raise Exception('Failed to create device flow')
print(flow['message'])
result = app.acquire_token_by_device_flow(flow)
if 'access_token' in result:
headers={'Authorization': 'Bearer ' + result['access_token']}
# get the site id
result = requests.get(f'{ENDPOINT}/sites/{SHAREPOINT_HOST_NAME}:/sites/{SITE_NAME}', headers=headers)
result.raise_for_status()
site_info = result.json()
site_id = site_info['id']
# get the drive id
result = requests.get(f'{ENDPOINT}/sites/{site_id}/drive', headers=headers)
result.raise_for_status()
drive_info = result.json()
drive_id = drive_info['id']
# download a file
file_path = 'General/Test Doc.docx' # replace this with the file you want to download
file_url = urllib.parse.quote(file_path)
result = requests.get(f'{ENDPOINT}/drives/{drive_id}/root:/{file_url}', headers=headers)
result.raise_for_status()
file_info = result.json()
file_id = file_info['id']
result = requests.get(f'{ENDPOINT}/drives/{drive_id}/items/{file_id}/content', headers=headers)
result.raise_for_status()
open(file_info['name'], 'wb').write(result.content)
else:
raise Exception('no access token in result')
@gbrault
Copy link

gbrault commented Apr 25, 2021

It seems you have one more step now. From the latest of your step you need to get the download url:

downloadUrl = result['@microsoft.graph.downloadUrl']
download =   requests.get(downloadUrl )
# the content is download.content

@timsschoen
Copy link

Just want to say thank you, this solved a problem for me today!

@drmayu7
Copy link

drmayu7 commented Nov 14, 2022

thank you! awesome job

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment