My app uses delegated user access tokens to interact with the MSFT graph api. They have the Calendars.ReadWrite.Shared
permission. When making requests to https://graph.microsoft.com/v1.0/subscriptions in production with the following request body:
{
"changeType": "created,updated,deleted",
"notificationUrl": <https_app_notification_url>,
"resource": "/me/calendars/<calendar_id>/events",
"expirationDateTime": (datetime.now(timezone.utc) + timedelta(minutes=4200)).isoformat(),
"clientState": <a_crypto_random_string>
}
almost every time the response is an error with the following in the response body:
[Status Code: Forbidden; Reason: Access is denied. Check credentials and try again.]
The most recent occurrence of this error had the following innerError
in the response:
{'date': '2020-05-13T20:58:09', 'request-id': '1448e490-9e45-4a08-9aab-dd9c996c18db'}
This happens even when trying to subscribe to the user's own default calendar.
The strange thing is that the exact same code, when run on my local machine and tunneled to the web via ngrok to expose my app's notificationUrl endpoint, is able to consistently get a 201 from the MSFT's subscriptions endpoint.
I've checked the system time on the server with the date
command and there's less than 1 second difference between my local machine and the server. So I don't think the expirationDateTime
field is the issue; it's got 30 minutes of buffer built in as I believe the max according to the docs is 4230.
Should I be requesting additional permissions in the oauth scopes for the user access tokens? The docs say that Calendars.Read
is enough so I would've thought Calendars.ReadWrite.Shared
would do it. Or am I missing something else?