I have an Azure AD Daemon application that is attempting to grab tasks from a desired planner. I've gone ahead and provided the necessary application permissions to try and grab the plan. I keep getting a "The requested item is not found" error despite using the correct Planner ID to grab the data. Is there a permission that I am missing or an issue with my code? I typically use VS code to run the python file with the command python application.py parameters.json.
Below is the python code I run for the application.
import sys # For simplicity, we'll read config file from 1st CLI param sys.argv[1]
import json
import logging
import requests
import msal
# Optional logging
# logging.basicConfig(level=logging.DEBUG)
config = json.load(open(sys.argv[1]))
# Create a preferably long-lived app instance which maintains a token cache.
app = msal.ConfidentialClientApplication(
config["client_id"], authority=config["authority"],
client_credential=config["secret"],
# token_cache=... # Default cache is in memory only.
# You can learn how to use SerializableTokenCache from
# .SerializableTokenCache
)
# The pattern to acquire a token looks like this.
result = None
# Firstly, looks up a token from cache
# Since we are looking for token for the current app, NOT for an end user,
# notice we give account parameter as None.
result = app.acquire_token_silent(config["scope"], account=None)
if not result:
logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
result = app.acquire_token_for_client(scopes=config["scope"])
if "access_token" in result:
# Calling graph using the access token
graph_data = requests.get( # Use token to call downstream service
config["endpoint"],
headers={'Authorization': 'Bearer ' + result['access_token']}, ).json()
print("Graph API call result: ")
print(json.dumps(graph_data, indent=2))
else:
print(result.get("error"))
print(result.get("error_description"))
print(result.get("correlation_id")) # You may need this when reporting a bug
Below is the parameters.json I use with the various ID's required for the application to run
{
"authority": ";,
"client_id": "client_id",
"scope": [ "/.default" ],
"secret": "Secret_Client",
"endpoint": ".0/planner/plans/plan_id"
}
The id names are only placeholders, just imagine them being in there.
Here are the perms currently assigned to the application. Help would be appreciated.
I have an Azure AD Daemon application that is attempting to grab tasks from a desired planner. I've gone ahead and provided the necessary application permissions to try and grab the plan. I keep getting a "The requested item is not found" error despite using the correct Planner ID to grab the data. Is there a permission that I am missing or an issue with my code? I typically use VS code to run the python file with the command python application.py parameters.json.
Below is the python code I run for the application.
import sys # For simplicity, we'll read config file from 1st CLI param sys.argv[1]
import json
import logging
import requests
import msal
# Optional logging
# logging.basicConfig(level=logging.DEBUG)
config = json.load(open(sys.argv[1]))
# Create a preferably long-lived app instance which maintains a token cache.
app = msal.ConfidentialClientApplication(
config["client_id"], authority=config["authority"],
client_credential=config["secret"],
# token_cache=... # Default cache is in memory only.
# You can learn how to use SerializableTokenCache from
# https://msal-python.rtfd.io/en/latest/#msal.SerializableTokenCache
)
# The pattern to acquire a token looks like this.
result = None
# Firstly, looks up a token from cache
# Since we are looking for token for the current app, NOT for an end user,
# notice we give account parameter as None.
result = app.acquire_token_silent(config["scope"], account=None)
if not result:
logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
result = app.acquire_token_for_client(scopes=config["scope"])
if "access_token" in result:
# Calling graph using the access token
graph_data = requests.get( # Use token to call downstream service
config["endpoint"],
headers={'Authorization': 'Bearer ' + result['access_token']}, ).json()
print("Graph API call result: ")
print(json.dumps(graph_data, indent=2))
else:
print(result.get("error"))
print(result.get("error_description"))
print(result.get("correlation_id")) # You may need this when reporting a bug
Below is the parameters.json I use with the various ID's required for the application to run
{
"authority": "https://login.microsoftonline/tenant_id",
"client_id": "client_id",
"scope": [ "https://graph.microsoft/.default" ],
"secret": "Secret_Client",
"endpoint": "https://graph.microsoft/v1.0/planner/plans/plan_id"
}
The id names are only placeholders, just imagine them being in there.
Here are the perms currently assigned to the application. Help would be appreciated.
Share Improve this question asked Mar 20 at 22:24 BrianBrian 111 bronze badge 1- Could you try listing all plans and see if you are getting correct response or not? – Sridevi Commented Mar 25 at 2:59
1 Answer
Reset to default 0The error usually occurs if you are using wrong plan ID that does not exist in your planner.
Initially, I too got same error when I tried to get the plan details with wrong plan ID via Graph Explorer:
GET https://graph.microsoft/v1.0/planner/plans/CVkxxxxxxxxxxxx
As you mentioned that you are using correct planner ID and still unable to grab details, once cross-check how the plan was created.
In my case, I created plan with below API request via Graph Explorer:
POST https://graph.microsoft/v1.0/planner/plans
{
"container": {
"url": "https://graph.microsoft/v1.0/groups/groupID"
},
"title": "Test-Plan01"
}
Response:
You can retrieve these plan details by either filtering plans with owner or use direct call to list plans within group.
Filtering Owner with Group ID:
GET https://graph.microsoft/v1.0/planner/plans?$filter=owner eq 'groupID'
Response:
List planner plans within group:
GET https://graph.microsoft/v1.0/groups/groupId/planner/plans
Response:
After getting this correct plan ID, you can now call this API and grab the details:
GET https://graph.microsoft/v1.0/planner/plans/Lk3Gxxxxxxxxxxxx
Response:
When I ran your code in my environment with above plan Id, I got the results successfully like this:
import sys # For simplicity, we'll read config file from 1st CLI param sys.argv[1]
import json
import logging
import requests
import msal
# Optional logging
logging.basicConfig(level=logging.INFO)
# Read configuration from the JSON file provided as a CLI argument
try:
with open(sys.argv[1]) as config_file:
config = json.load(config_file)
except IndexError:
print("Error: Please provide the path to the configuration JSON file as an argument.")
sys.exit(1)
except FileNotFoundError:
print("Error: The configuration file was not found.")
sys.exit(1)
# Create a long-lived app instance which maintains a token cache.
app = msal.ConfidentialClientApplication(
config["client_id"], authority=config["authority"],
client_credential=config["secret"],
)
# Try to get a token from cache
result = app.acquire_token_silent(config["scope"], account=None)
if not result:
logging.info("No token found in cache. Requesting a new one from Azure AD.")
result = app.acquire_token_for_client(scopes=config["scope"])
if "access_token" in result:
# Make a request to Microsoft Graph API using the access token
response = requests.get(
config["endpoint"],
headers={'Authorization': f'Bearer {result["access_token"]}'}
)
if response.status_code == 200:
graph_data = response.json()
print("Graph API call result:")
print(json.dumps(graph_data, indent=2))
else:
print(f"Error: Unable to fetch data from Graph API (Status Code: {response.status_code})")
print(response.text)
else:
print("Authentication failed.")
print(f"Error: {result.get('error')}")
print(f"Error Description: {result.get('error_description')}")
print(f"Correlation ID: {result.get('correlation_id')}")
parameters.json:
{
"authority": "https://login.microsoftonline/tenant_id",
"client_id": "client_id",
"scope": [ "https://graph.microsoft/.default" ],
"secret": "Secret_Client",
"endpoint": "https://graph.microsoft/v1.0/planner/plans/plan_id"
}
Response: