Download files from personal OneDrive using Python

I managed to do it. I'm not sure if it's the best way but it is working now. It's running automatically every hour and I don't need to touch it.

I followed the information on

This is what I did.

Azure Portal

  • Create an application. Azure Active Directory -> App Registrations -> Applications from personal account
  • In Supported account types, choose the one that has personal Microsoft accounts.
  • In Redirect URI, choose Public client/native. We'll add the specific URI later.
  • In the application details, in the section Overview, take note of the Application (client) ID. We'll need this later.
  • In the section Authentication, click Add a Platform and choose Desktop + devices. You can use your own, I chose one of the suggested:
  • In the section API permissions, you have to add all the permissions that your app will use. I added User.Read, Files.ReadWrite and offline_access. The offline_access is to be able to get the refresh token, which will be crucial to keep the app running without asking the user to login.
  • I did not create any Certificate or Secret.


Looks like to get a token for the first time we have to use a browser or emulate something like that.

There must be a programmatic way to do this, but I had no idea how to do it. I also thought about using Selenium for this, but since it's only one time and my app will request tokens every hour (keeping the tokens fresh), I dropped that idea.

If we add new permissions, the tokens that we have will become invalid and we have to do this manual part again.

  • Open a browser and go to the URL below. Use the Scopes and the Redirect URI that you set up in Azure Portal.

That URL will redirect you to the Redirect URI that you set up and with a code=something in the URL. Copy that something.

  • Do a POST request with type FORM URL Encoded. I used for this.


Form URL: grant_type=authorization_code&client_id=your_app_client_id&code=use_the_code_returned_on_previous_step

This will return an Access Token and a Refresh Token. Store the Refresh Token somewhere. I'm saving it in a file.


# Build the POST parameters
params = {
          'grant_type': 'refresh_token', 
          'client_id': your_app_client_id,
          'refresh_token': refresh_token_that_you_got_in_the_previous_step

response ='', data=params)

access_token = response.json()['access_token']
new_refresh_token = response.json()['refresh_token']

# ^ Save somewhere the new refresh token. 
# I just overwrite the file with the new one. 
# This new one will be used next time.

header = {'Authorization': 'Bearer ' + access_token}

# Download the file
response = requests.get('' +
                         PATH_TO_FILE + '/' + FILE_NAME + ':/content', headers=header)

# Save the file in the disk 
with open(file_name, 'wb') as file:

So basically, I have the Refresh Token always updated.

I call the Token endpoint using that Refresh Token, and the API gives me an Access Token to use during the current session and a new Refresh Token.

I use this new Refresh Token the next time I run the program, and so on.