acr
acr

Reputation: 1746

Upload file to onedrive personal using python in non-interactive way

I have seen some older method using onedrive sdk, seems like those are not working now. This is one of the method I got after some research. But it is not working

import msal
import requests

# Azure AD app credentials
client_id = 'xxx9846xxxx'
client_secret = 'xxxTdxxx'
tenant_id = 'xxx-xxxx'

# Authority URL for your tenant
authority = f'https://login.microsoftonline.com/{tenant_id}'

# Scopes needed for OneDrive file operations
scopes = ['https://graph.microsoft.com/.default']

# Initialize the MSAL ConfidentialClientApplication
app = msal.ConfidentialClientApplication(
    client_id,
    client_credential=client_secret,
    authority=authority
)

# Get the access token
token_response = app.acquire_token_for_client(scopes=scopes)
access_token = token_response.get('access_token')

if not access_token:
    raise Exception("Could not acquire access token")


# Define the file to upload
file_path = 'C:/test.csv'

# Microsoft Graph API endpoint for OneDrive (using Application Permissions)
upload_url = 'https://graph.microsoft.com/v1.0/me/drive/root:/Documents/' + file_name + ':/content'


# Open the file in binary mode
with open(file_path, 'rb') as file:
    file_content = file.read()

# Make the PUT request to upload the file
headers = {
    'Authorization': f'Bearer {access_token}',
    'Content-Type': 'application/octet-stream'
}

response = requests.put(upload_url, headers=headers, data=file_content)

# Check if the file upload was successful
if response.status_code == 201:
    print(f'File uploaded successfully to OneDrive: {file_name}')
else:
    print(f'Error uploading file: {response.status_code}, {response.text}')

I am geting below error:

Error uploading file: 400, {"error":{"code":"BadRequest","message":"/me request is only valid with delegated authentication flow.","innerError":{"date":"2025-01-13T17:06:35","request-id":"5959d049-9ad7-4ced-b6fc-00ddddd242","client-request-id":"5959d049-9ad7-4ced-b6fc-0079ddddd"}}}

How to resolve this error ? or any alternative way to upload the files

Update :

I have created a new app registration which support "Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)"

These are the API permissions I have added:

enter image description here

updated code :

import requests

# Replace with your details
client_id = 'xxxxx'
client_secret = 'xxxx'
tenant_id = '052c8b5b-xxxx'
filename = 'C:/test.csv'
onedrive_folder = 'CloudOnly/test'
user_id = 'xxxx-e7d1-44dc-a846-5exxxx'

# Get the access token
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(url, data=data)
token = response.json().get('access_token')

# Upload the file to OneDrive
headers = {
    'Authorization': f'Bearer {token}',
    'Content-Type': 'application/octet-stream'
}

file_content = open(filename, 'rb').read()

upload_url = f'https://graph.microsoft.com/v1.0/users/{user_id}/drive/root:/{onedrive_folder}/{filename.split("/")[-1]}:/content'

upload_response = requests.put(upload_url, headers=headers, data=file_content)

if upload_response.status_code == 201:
    print('File uploaded successfully!')
else:
    print('Error uploading file:', upload_response.json())

But this gives me error:

Error uploading file: {'error': {'code': 'BadRequest', 'message': 'Tenant does not have a SPO license.', 'innerError': {'date': '2025-01-14T02:15:47', 'request-id': 'cf70193e-1723-44db-9f5e-xxxxx', 'client-request-id': 'cf70193e-1723-44db-9f5e-xxxx'}}}

Upvotes: 0

Views: 84

Answers (1)

Pratik Jadhav
Pratik Jadhav

Reputation: 848

Initially, I registered Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)" Microsoft Entra ID application:

enter image description here

Error uploading file: 400, {"error":{"code":"BadRequest","message":"/me request is only valid with delegated authentication flow.

I came across same error, When I ran the python code which you provided by using /me endpoint.

enter image description here

Note: For uploading file to OneDrive-Personal, Must have to use delegated flow where user-interaction is involved and Must use /me endpoint only; As it not possible with application type API permission and client-credential flow(non-user-interactive).

To resolve the error, Using delegated type, authorization code flow where user-interaction is involved.

Added delegated type Files.ReadWrite.All API Permission and Granted Admin consent like below:

enter image description here

Configured Authentication tab of application like below:

enter image description here

enter image description here

Use below modified python script with delegated flow using authorization code flow:

import requests
from msal import PublicClientApplication
import os
import time

CLIENT_ID = '<client-id>';
CLIENT_SECRET = '<client-secret>';
file_name= "<file-name to whom you want to upload>";
file_path = "<file-path>";

authority_url = 'https://login.microsoftonline.com/common'
scopes = ['Files.ReadWrite.All']
onedrive_folder ="Documents";

app = PublicClientApplication(CLIENT_ID, authority=authority_url)

# Simplistic approach to illustrate the flow
redirect_uri = 'http://localhost:8000/callback'
url = app.get_authorization_request_url(scopes, redirect_uri=redirect_uri)
print("Please go to this URL and sign-in:", url)

# After sign-in, receive a callback with a code
code = input("Enter the code you received: ")
result = app.acquire_token_by_authorization_code(code, scopes=scopes, redirect_uri=redirect_uri)

if 'access_token' in result:
    access_token = result['access_token']
    print("Access token acquired.")
else:
    print(result.get('error'))
    print(result.get('error_description'))
    exit(1)


upload_url = f'https://graph.microsoft.com/v1.0/me/drive/root:/{onedrive_folder}/{file_name}:/content'

# Open the file in binary mode
with open(file_path, 'rb') as file:
    file_content = file.read()

# Make the PUT request to upload the file
headers = {
    'Authorization': f'Bearer {access_token}',
    'Content-Type': 'application/octet-stream'
}

response = requests.put(upload_url, headers=headers, data=file_content)

# Check if the file upload was successful
if response.status_code == 201:
    print(f'File uploaded successfully to OneDrive: {onedrive_folder}:/{file_name}')
else:
    print(f'Error uploading file: {response.status_code}, {response.text}')

Copy the authorization_code from browser and Paste at Enter the code you received:

enter image description here

Response:

enter image description here

I've verified same from OneDrive Portal as well, File TestUploadOnedrive.xlsx was uploaded successfully.

enter image description here

Error uploading file: {'error': {'code': 'BadRequest', 'message': 'Tenant does not have a SPO license.', '

To resolve this error, User should have active Office 365 E3 license or Office 365 E5 license. Refer this SO Thread by Rukmini.

If still issue persist, Check thisMicrosoft QnA by Carl-Zhao-MSFT

Reference:

Upload the content of Drive Item

Refer this SO thread for Tenant does not have a SPO license. by Dan Kershaw - MSFT.

MsDoc on authorization_code flow

Upvotes: 1

Related Questions