5

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.

Community
  • 1
  • 1
Fabrice Dugas
  • 509
  • 1
  • 5
  • 15

1 Answers1

4

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.

Fabrice Dugas
  • 509
  • 1
  • 5
  • 15
  • Thanks for the feedback Fabrice. Graph is absolutely the recommended API to use. It actually uses the Outlook endpoint under the covers. We have a doc here that attempts to explain the difference and why you might choose one over the other: https://learn.microsoft.com/en-us/outlook/rest/compare-graph-outlook. We are working on unifying the REST API story to be super-clear that Graph is the preferred way. – Jason Johnston Sep 18 '17 at 12:58
  • Cool. Thank you for your comment. I guess it's that point in time where you are trying to transition from one version to the other hence my last phrase. – Fabrice Dugas Sep 19 '17 at 14:26
  • 2
    I fully agree with your despair at Microsoft's documentation for this. There are no simple python example, only a Django server build tutorial... – Matteo Ferla Jun 01 '18 at 15:25
  • Where app_id is your username? and client_secret is your password? – partydog Nov 06 '18 at 20:19
  • @partydog Hmm no? Not sure what you mean by username and password. But from what I remember, in your Microsoft Graph web view you can get your application identifier (app_id in my exemple) and generate a key to use in your code (client_secret). – Fabrice Dugas Nov 09 '18 at 21:18
  • 1
    This line: `'scope': 'https://graph.microsoft.com/.default'` needs a comma at the end – shanecandoit Oct 02 '20 at 20:51