I am using the Python msal package and the ClientCredentialFlow
when trying to authenticate to the MS-project odata API using following script:
import requests
import msal
def get_access_token():
# Set your Azure AD tenant ID, client ID (Application ID), and client secret
tenant_id = "your_tenant_id"
client_id = "your_client_id"
client_secret = "your_client_secret"
# Create a confidential client application
confidential_client = msal.ConfidentialClientApplication(
client_id,
authority=f"https://login.microsoftonline.com/{tenant_id}",
client_credential=client_secret
)
# Define the scope (permissions) you want to request
scopes = ["https://your_tenant_name.sharepoint.com/.default"] # Replace "your_tenant_name" with your actual tenant name
# Get an access token using the "Client Credentials" flow
result = confidential_client.acquire_token_for_client(scopes=scopes)
if "access_token" in result:
access_token = result["access_token"]
return access_token
else:
print("Failed to obtain access token.")
return None
def get_project_data():
# Set the API endpoint URL
ms_project_api_url = 'https://your_tenant_name.sharepoint.com/sites/your_project_instance/_api/ProjectData/'
# Get the access token
access_token = get_access_token()
if access_token:
# Create the headers with the access token
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
# Make the API request
response = requests.get(ms_project_api_url, headers=headers)
if response.status_code == 200:
# The request was successful, you can process the response here
print("Data successfully retrieved:")
print(response.json()) # If the API returns JSON data
else:
# The request was not successful, display the error message
print("Error while retrieving data. Status code:", response.status_code)
print(response.text)
else:
print("Failed to obtain access token.")
if __name__ == "__main__":
get_project_data()
Which scope do I need and what permissions are needed in the Appregistration via Azure?
As far as I understood I need some application-permissions, but can't find some which belong to MS Project.
I just found following delegated permissions in SharePoint group: Project.Read
, Project.Write
, ProjectWebApp.FullControl
, ProjectWebAppReporting.Read
and tried them out:
I tried with different scopes, e.g.:
["https://mytenant.sharepoint.com/.default"]
here I got an access-token, but no access to the API, get_project_data()
fails with:
The request was not valid or is malformed.
Note that, client credentials flow only works with permissions of Application
type but they are not currently available for MS Project.
I registered one Azure AD application and added below Delegated API permissions by granting consent:
When I ran your code in my environment, I too got same error as below:
import requests
import msal
def get_access_token():
# Set your Azure AD tenant ID, client ID (Application ID), and client secret
tenant_id = "tenantID"
client_id = "appID"
client_secret = "secret"
# Create a confidential client application
confidential_client = msal.ConfidentialClientApplication(
client_id,
authority=f"https://login.microsoftonline.com/{tenant_id}",
client_credential=client_secret
)
# Define the scope (permissions) you want to request
scopes = ["https://xxxxxxxxxx.sharepoint.com/.default"] # Replace "your_tenant_name" with your actual tenant name
# Get an access token using the "Client Credentials" flow
result = confidential_client.acquire_token_for_client(scopes=scopes)
if "access_token" in result:
access_token = result["access_token"]
return access_token
else:
print("Failed to obtain access token.")
return None
def get_project_data():
# Set the API endpoint URL
ms_project_api_url = 'https://xxxxxxxxxx.sharepoint.com/sites/pwademosite/_api/ProjectData/'
# Get the access token
access_token = get_access_token()
#print(access_token)
if access_token:
# Create the headers with the access token
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
# Make the API request
response = requests.get(ms_project_api_url, headers=headers)
if response.status_code == 200:
# The request was successful, you can process the response here
print("Data successfully retrieved:")
print(response.json()) # If the API returns JSON data
else:
# The request was not successful, display the error message
print("Error while retrieving data. Status code:", response.status_code)
print(response.text)
else:
print("Failed to obtain access token.")
if __name__ == "__main__":
get_project_data()
Response:
To authorize to MS Project ODATA API, you need to make use of Delegated flows like username password, interactive flows etc... that works with permissions of
Delegated
type.
In my case, I changed to username password flow for which below option should be enabled(wait for few minutes after enabling as there will be delay):
When I ran below modified code with username password flow, I got Project data response successfully:
import requests
import msal
def get_access_token():
# Set your Azure AD tenant ID, client ID (Application ID), and client secret
tenant_id = "tenantID"
client_id = "appID"
username = "admin@xxxxxxxxxx.onmicrosoft.com"
password = "xxxxxxxxxxxx"
# Create a public client application
public_client = msal.PublicClientApplication(
client_id,
authority=f"https://login.microsoftonline.com/{tenant_id}",
)
# Define the scope (permissions) you want to request
scopes = ["https://xxxxxxxx.sharepoint.com/.default"] # Replace "your_tenant_name" with your actual tenant name
# Get an access token using the "Username Password" flow
result = public_client.acquire_token_by_username_password(
username=username,
password=password,
scopes=scopes,
)
if "access_token" in result:
access_token = result["access_token"]
return access_token
else:
print("Failed to obtain access token.")
return None
def get_project_data():
# Set the API endpoint URL
ms_project_api_url = 'https://xxxxxxxxx.sharepoint.com/sites/pwademosite/_api/ProjectData/'
# Get the access token
access_token = get_access_token()
#print(access_token)
if access_token:
# Create the headers with the access token
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
# Make the API request
response = requests.get(ms_project_api_url, headers=headers)
if response.status_code == 200:
# The request was successful, you can process the response here
print("\nData successfully retrieved:\n")
print(response.content)
else:
# The request was not successful, display the error message
print("Error while retrieving data. Status code:", response.status_code)
print(response.text)
else:
print("Failed to obtain access token.")
if __name__ == "__main__":
get_project_data()
Response: