Search code examples
python-3.xclientcredentialsadalhttp-status-code-401

Python Adal - Can't use Access Token to retrieve Outlook Messages


I've recently been attempting to port a email extraction process from Powershell to Python using the Azure active directory for Python library. I've been attempting to use the acquire_token_with_client_credentials function to do this but I've hit a snag.

I can use the code below to return an access code but I can't use the resulting token to return any mailbox items.

I've managed to create a native app and successfully access messages using acquire_token_with_username_password but can't get that set of code to work on my remote desktop as it prints an error reading:

"Due to a configuration change made by your administrator, or because you moved to a new location, you must use multi-factor authentication"

I've had a ready of the client credentials flow but still can't get the example below to work. Can anyone see where I'm going wrong?

def test8():

import adal
import requests

authority_url = "https://login.microsoftonline.com/"+lf_tenantid
context = adal.AuthenticationContext(
    authority_url,
    validate_authority=True,
    api_version=None
)

resource = 'https://outlook.office.com/'

token = context.acquire_token_with_client_credentials(
    resource=resource,
    client_id = etl_clientid2,
    client_secret = etl_clientsecret2
)

access_token = token['accessToken']

print(token)
#######################################NONE OF THIS PART WORKS
#######################################
#######################################

folder_id = etl_folderid
url = "https://outlook.office.com/api/v2.0/me/MailFolders/"+folder_id+"/messages"

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

r = requests.get(url, headers=headers)
print(r)

Solution

  • For anyone who's interested, this is the code I used to solve my access token issue:

    def save_windows_refreshtoken(app_name, client_id, client_secret):
    
    #import adal
    #import requests
    import json
    import pandas as pd
    
    
    # OAuth endpoints given in Outlook API documentation
    authorization_base_url = 'https://login.microsoftonline.com/common/oauth2/authorize'
    token_url = 'https://login.microsoftonline.com/common/oauth2/token' #provides a refresh and access token
    
    redirect_uri = "http://localhost:8000"
    
    from requests_oauthlib import OAuth2Session
    outlook = OAuth2Session(client_id,redirect_uri=redirect_uri)
    
    # Redirect  the user owner to the OAuth provider (i.e. Outlook) using an URL with a few key OAuth parameters.
    authorization_url, state = outlook.authorization_url(authorization_base_url)
    print('Please go here and authorize,', authorization_url)
    
    #The above redirects you to a localhost page (which is blank) but returns a string containing a code which can be used below
    #rememebr the search for "&" because there's a couple of bits of data after the code that need to be deleted from the code string before it can be used
    
    # Get the authorization verifier code from the callback url
    redirect_response = input('Paste the full redirect URL here:')
    
    # Fetch the access token
    token = outlook.fetch_token(token_url,client_secret=client_secret,code=redirect_response)
    
    
    #convert the returned token json into a dataframe
    j_dump = json.dumps(token, sort_keys=True,indent=4, separators=(',', ': ')) #pull out the value data from the json file, messages are stored in value
    
    df = pd.read_json(j_dump) #read the json file into a dataframe
    
    first_row = df.iloc[0] #pull the first row so we can format a new table from it
    
    d = {
        'app_name' : pd.Series([app_name]),
        'refresh_token' : pd.Series([first_row.refresh_token])
        }
    data = pd.DataFrame(d)