Trying to access the "https://graph.microsoft.com/v1.0/me/drive"
endpoint via a Flask application results in the following response:
{
"error": {
"code": "HostNotFound",
"innerError": {
"client-request-id": "{xxx}",
"date": "2024-04-02T15:47:03",
"request-id": "{yyy}"
},
"message": "Target '{zzz}-my.sharepoint.com' is not found."
}
print(token["scope"])
# openid profile email https://graph.microsoft.com/Application.Read.All https://graph.microsoft.com/Files.Read https://graph.microsoft.com/Files.Read.All https://graph.microsoft.com/Files.ReadWrite.All https://graph.microsoft.com/Sites.Read.All https://graph.microsoft.com/Sites.ReadWrite.All https://graph.microsoft.com/User.Export.All https://graph.microsoft.com/User.Read https://graph.microsoft.com/.default
"https://graph.microsoft.com/v1.0/applications"
or "https://graph.microsoft.com/v1.0/me"
Therefore, I assume that the token generation is not the issue.As I am still trying to get the access to work in the first place, the tokens are currently passed around via session, with the decorator executing the final request after appending the Authorization header. This is not my intended long term use / implementation. I am happy about any suggestion / industry standard, how to properly handle and incorporate this. However, the focus of this question is mainly about why I am not able to access my personal OneDrive files via the Microsoft Graph API.
app.py
import json
from functools import wraps
import msal
import requests
from flask import Flask, session, request, redirect, make_response, url_for
app = Flask(__name__)
with open("delegated_config.json") as file:
config = json.load(file)
app.config.update(config)
client_instance = msal.ConfidentialClientApplication(
client_id=app.config["application_id"],
client_credential=app.config["client_secret"],
authority=app.config["authority_url"]
)
def initiate_auth_flow():
"""Authentication with Access Token"""
if not session.get("auth_flow"):
authorization = client_instance.initiate_auth_code_flow(
app.config["scope"], redirect_uri=app.config["redirect_uri"]
)
session["auth_flow"] = authorization
authorization = session.get("auth_flow")
# Will redirect to "generate_token()"
return make_response(redirect(authorization["auth_uri"]))
def get_token(func):
@wraps(func)
def wrapper(*args, **kwargs):
if not session.get("access_token"):
session["execute_func"] = func.__name__
return initiate_auth_flow()
else:
url = func(*args, **kwargs)
return requests.get(
url, headers={"Authorization": f"Bearer {session['access_token']}"}).json()
return wrapper
# Redirect route after logging in and confirming permissions
@app.route("/generate_token")
def generate_token():
query_string = request.args
token = client_instance.acquire_token_by_auth_code_flow(session["auth_flow"],
auth_response=query_string)
session["access_token"] = token["access_token"]
return redirect(url_for(session["execute_func"]))
# WORKS
@app.route("/me")
@get_token
def me():
return "https://graph.microsoft.com/v1.0/me"
# WORKS
@app.route("/all_applications")
@get_token
def all_applications():
return "https://graph.microsoft.com/v1.0/applications"
# DOES NOT WORK, ERROR AT BEGINNING OF QUESTION
@app.route("/all_drives")
@get_token
def all_drives():
return "https://graph.microsoft.com/v1.0/me/drive"
# DOES NOT WORK
@app.route("/private_drive")
@get_token
def private_drive():
return "https://api.onedrive.com/v1.0/me/drive"
# {"error": {"code": "invalidRequest", "message": "Invalid API or resource"}}
delegated_config.json
{
"SECRET_KEY": "{xxx}",
"application_id": "{yyy}",
"client_secret": "{zzz}",
"authority_url": "https://login.microsoftonline.com/{tenant_id}",
"scope": [ "https://graph.microsoft.com/.default" ],
"redirect_uri": "http://localhost:6123/generate_token"
}
Eventually figured it out myself. All I had to do is to NOT pass the specific authority_url of my tenant to the ConfidentialClientApplication
, so i.e.
client_instance = msal.ConfidentialClientApplication(
client_id=app.config["application_id"],
client_credential=app.config["client_secret"]
)
...which will lead to using the default authority_url
, i.e. https://login.microsoftonline.com/common
.
Thinking about it afterwards, it makes sense. The initial error code indicated, that Microsoft Graph was not able to find a OneDrive / Sharepoint for my user in the tenant. Since I wanted to access the data of my personal OneDrive however, which is not included in my organization, I was simply able to access it using the /common
endpoint, after authenticating myself with the application.