Trying to download my (personal) photos from OneDrive (want to backup them on my NAS)
Created an API Key in Azure Portal. Enterprise applications | All applications
Added "http://localhost" to redirect URL. Using a "Desktop Application" (so no client_secret allowed).
Added the following Rights to the API Key: application rights
User.Read
User.Export.All
Files.ReadWrite.All
Using (python) MSAL library:
$ pip list | grep msal
msal 1.32.0
msal-extensions 1.3.1
Using PublicClientApplication and "consumers" endpoint to create an app:
app = PublicClientApplication(
app_id,
authority="https://login.microsoftonline.com/consumers")
Browser opens, I confirm, browser gets redirected to localhost:
Authentication completed. You can close this window now.
Creating a token with the following scopes:
scopes = ["User.Read", "User.Export.All", "Files.ReadWrite.All"]
result = app.acquire_token_interactive(scopes=scopes)
Token gets returned.
Using that token to Download Infos for the Files stored:
request_url = 'https://graph.microsoft.com/v1.0/me/drive/root:/Bilder/Eigene Aufnahmen:/children'
That works fine and returns json information for all files in this folder, e.g.:
"@microsoft.graph.downloadUrl": "https://my.microsoftpersonalcontent.com/personal/bfc1c0d9bbadf7cd/_layouts/15/download.aspx?UniqueId=bbadf7cd-c0d9-20c1-80bf-042d00000000&Translate=false&tempauth=v1e.eyJzaXRlaWQiOiI0OTgwMzNhOC00MWVjLTQ4Y2QtYTg2YS0xYjYwNjViMmUyMDUiLCJhcHBfZGlzcGxheW5hbWUiOiJQZXJzb25hbCBadWdyaWZmIGF1ZiBPbmVEcml2ZSIsImFwcGlkIjoiNmNhZTJhMmEtNzAwOS00ZDY2LWE5MjgtYmU1ZjQ[...]
When using this URL to download the Photo, i get:
{"error":{"code":"unauthenticated","message":"Unauthenticated"}}
401
HTTP error 401 and "unauthenticated" message ..
Can someone point me to a direction?
If retrieving information about the folders using the access token works fine, why does it return 401 when trying to download the content of the file?
Full script is here:
#!/usr/bin/python3
import requests
import json
from msal import PublicClientApplication
### config
app_id = '6cae2a2a-XXX'
authority = 'https://login.microsoftonline.com/consumers'
scopes = ["User.Read", "User.Export.All", "Files.ReadWrite.All"]
### start main ###
### create app
app = PublicClientApplication(app_id, authority=authority)
### get access token
result = app.acquire_token_interactive(scopes)
if "access_token" in result:
print("Got access_token: " + result["access_token"])
else:
print(result.get("error"))
print(result.get("error_description"))
print(result.get("correlation_id")) # You may need this when reporting a bug
exit()
### try to download with access_token
request_url = 'https://graph.microsoft.com/v1.0/me/drive/root:/Bilder/Eigene Aufnahmen:/children'
headers = {"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Bearer " + result["access_token"]
}
response = requests.get(request_url, headers=headers)
print (response.text)
print (response.status_code)
print (json.dumps(response.json(), indent=3))
This works fine (listing all files) .. changing the URL to the Download URL of one of the files gives 401 error ..
As for the permissions the Application has:
$ az ad app permission list --id 6cae2a2a-7009-4d66-a928-XXX
[
{
"resourceAccess": [
{
"id": "863451e7-0667-486c-a5d6-d135439485f0",
"type": "Scope"
},
{
"id": "405a51b5-8d8d-430b-9842-8be4b0e9f324",
"type": "Scope"
},
{
"id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
"type": "Scope"
}
],
"resourceAppId": "00000003-0000-0000-c000-000000000000"
}
]
$ az ad app permission list-grants --id 6cae2a2a-7009-4d66-a928-XXX
[
{
"clientId": "64facadb-8227-464e-aa21-XXX",
"consentType": "AllPrincipals",
"id": "28r6ZCeCTkaqIZfQJobl9BMQHNlpjqxEqXXX",
"principalId": null,
"resourceId": "d91c1013-8e69-44ac-abb8-8508276a8376",
"scope": " Files.ReadWrite.All User.Export.All User.Read offline_access openid profile"
}
]
To download the Picture from OneDrive Personal account using Python MSAL
Initially, I Registered Microsoft Entra ID Application with Supported Account type of Microsoft Personal Account Users only:
Configured Authentication tab with Mobile and desktop applications
and Added Redirect_URI:
Added delegated type Files.ReadWrite.All
API permission like below:
{"error":{"code":"unauthenticated","message":"Unauthenticated"}}
To resolve the error you are getting, Needs to use tempauth
in Authorization.
import requests
import msal
import re
# Replace with your App Registration details
CLIENT_ID = "<APPLICATION_ID>" # Azure App Registration Client ID
AUTHORITY = "https://login.microsoftonline.com/consumers" # Use 'consumers' for personal accounts
SCOPES = ["Files.ReadWrite.All"]
# Initialize MSAL Public Client
app = msal.PublicClientApplication(CLIENT_ID, authority=AUTHORITY)
# Authenticate interactively (opens browser)
token_result = app.acquire_token_interactive(SCOPES)
if not token_result or "access_token" not in token_result:
print("[!] Authentication failed.")
exit()
access_token = token_result["access_token"]
headers = {"Authorization": f"Bearer {access_token}"}
# File name (from OneDrive root)
file_name = "<FILE-PATH>"
# Request URL to get file metadata
file_metadata_url = f"https://graph.microsoft.com/v1.0/me/drive/root:/{file_name}"
# Get file metadata
response = requests.get(file_metadata_url, headers=headers)
if response.status_code != 200:
print(f"[!] Error getting file details: {response.json()}")
exit()
# Extract download URL
file_metadata = response.json()
download_url = file_metadata.get("@microsoft.graph.downloadUrl")
if not download_url:
print("[!] Download link not found.")
exit()
print(f"Download URL: {download_url}")
# Extract 'tempauth' token from URL
tempauth_match = re.search(r"tempauth=([^&]+)", download_url)
if not tempauth_match:
print("[!] Failed to extract 'tempauth' token.")
exit()
tempauth_token = tempauth_match.group(1)
# Set new headers using 'tempauth' instead of Bearer token
download_headers = {"Authorization": f"Bearer {tempauth_token}"}
# Download file
download_response = requests.get(download_url, headers=download_headers)
if download_response.status_code == 200:
with open(file_name, "wb") as file:
file.write(download_response.content)
print(f" File downloaded successfully: {file_name}")
else:
print(f"[!] Error downloading file: {download_response.status_code}")
print(download_response.text)
Grant the permission to application to access your OneDrive Personal Account:
Response:
Also, When I clicked that download URL: