Authentication in Outlook 365 api

Fabrice Dugas picture Fabrice Dugas · Sep 17, 2017 · Viewed 12.9k times · Source

My use case is: make a script that will run every hour to extract information about a user's calendar.

My script runs in Python and I get a token but I am unable to get the user's events. I have registered my app in the Microsoft Application Registration Portal and given the Calendar.read application permission. An administrator gave consent by accessing the /adminconsent endpoint.

Here is my code to get the token (documentation here):

url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
data = {
    'grant_type': 'client_credentials',
    'client_id': app_id,
    'scope': 'https://graph.microsoft.com/.default',  <--- Really not sure about this here
    'client_secret': client_secret,
}
r = requests.post(url, data=data)
token = r.json().get('access_token')

What scope am I suppose to use? The documentation only speaks of the one above.

And to read the user's calendar:

url = 'https://outlook.office.com/api/v2.0/users/{}/events'.format(user_email)
headers = {
    'Authorization': 'Bearer {}'.format(token)
}
r = requests.get(url, headers=headers)

I am not sure of the users/{user_email}/ part.

I get an access token but I get the following error when trying to read the user's calendar:

Response [401]

The access token is acquired using an authentication method that is too weak to allow access for this application. Presented auth strength was 1, required is 2.

Answer

Fabrice Dugas picture Fabrice Dugas · Sep 17, 2017

I have finally found it. I was very close.

I had to use Microsoft Graph API endpoint instead of Outlook Unified API endpoint.

The final code looks like:

import requests

# Get a token
url = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
data = {
    'grant_type': 'client_credentials',
    'client_id': app_id,
    'scope': 'https://graph.microsoft.com/.default'
    'client_secret': client_secret,
}
r = requests.post(url, data=data)
token = r.json().get('access_token')

# ...

# Use the token using microsoft graph endpoints
url = 'https://graph.microsoft.com/v1.0/users/{}/events'.format(user_email) # can also use the user_id (e.g. 12345-abcde-...)
headers = {
    'Authorization': 'Bearer {}'.format(token)
}
r = requests.get(url, headers=headers)

Microsoft's documentation really needs clarification. It has too many different APIs that do very similar things.