I am trying to download some data from a customer's Microsoft Dyanmics 365 CRM API. Below is my code written in Python 3.7, using MSAL (Microsoft Authentication Library) for Python.
import msal
import requests
class Downloader:
AUTHORITY = 'https://login.microsoftonline.com/common'
SCOPES = ["https://admin.services.crm.dynamics.com/user_impersonation"]
def __init__(self, client_id, client_credential, refresh_token):
self.client_id = client_id
self.client_credential = client_credential
self.refresh_token = refresh_token
def download(self):
application = msal.ConfidentialClientApplication(
client_id=self.client_id,
client_credential=self.client_credential,
authority=self.AUTHORITY,
token_cache=None)
response = application.acquire_token_by_refresh_token(self.refresh_token, self.SCOPES)
instances = requests.get(
'https://globaldisco.crm.dynamics.com/api/discovery/v1.0/Instances',
headers={'Authorization': 'Bearer ' + response['access_token']},
)
return response
When I run the download()
method I successfully get a response
that contains an Access Token but when I use it to GET instances
I get back HTTP Status Code 401 Access Denied.
My question is: Why am I getting 401 Access Denied and how can I fix my code to get 200 OK?
More data:
client_id
andclient_credential
identify a multi-tenant Azure App Registration I've setup. This app registration is not verified yet. It has these API Permissions (scopes) configured:
https://admin.services.crm.dynamics.com/user_impersonation
https://graph.microsoft.com/User.Read
refresh_token
has been generated based on Quickstart: Add sign-in with Microsoft to a Python web app. The quickstart goes through setting up a small Flask web application where a person can sign in via Microsoft Identity and grant permission for my app registration to impersonate them when later accessing the Dynamics 365 CRM API. I've setup the Flask app to use my App Registration and the two scopes above.Because my App Registration is not verified yet, I had an admin of the target tenet sign in via the Flask app, approve and give consent for my app registration to be used by the tenet org. I've tried both their refresh token and another non-admin person's refresh token. Both yield 401.
The tenet org (to which my customers' identities belong) is linked to a Dynamics 365 account.
Update:
When I view my app registration in my customer's (i.e. tenet's) Azure Portal under Enterprise Applications I can see the Common Data Service user_impersonation
permission under the Admin consent tab but it's missing from the User consent tab.
I'm trying to figure out whether this might explain why users are denied access and how to add the missing permission to User consent.