Mark
Mark

Reputation: 326

Use Python to call SharePoint API get 401 response while I have the token

I have registered my App in Azure with API permission as below:

enter image description here

Here is my python code.

import requests
from msal import ConfidentialClientApplication

client_id = "xxxxxxxxxxxxxxxxxxxxx"
client_secret = "yyyyyyyyyyyyyyyyyyyyy"
tenant_id = "tttttttttttttttttttttttttttttttttttttttt"
site_url = "https://{mytenent}.sharepoint.com/sites/mysite"
resource = "https://{mytenent}"

# Authenticate using client ID and secret
authority = f"https://login.microsoftonline.com/{tenant_id}"
app = ConfidentialClientApplication(
    client_id=client_id,
    authority=authority,
    client_credential=client_secret,
)

scope=[resource + "/.default"]
token_response = app.acquire_token_for_client(scopes=scope)


access_token = token_response.get("access_token") #token_response["access_token"]
print(access_token)

endpoint_url = f"{site_url}/_api/web"
headers = {
    "Authorization": "Bearer " + access_token,
    "Accept": "application/json;odata=verbose",
    "Content-Type": "application/json;odata=verbose",
}
print(endpoint_url)
response = requests.get(endpoint_url, headers=headers)

# Check for errors in the SharePoint API response
if response.status_code == 200:
    data = response.json()
    print("SharePoint Site Title:", data["d"]["Title"])
else:
    print("SharePoint API Error:")
    print("Status Code:", response.status_code)
    print("Response:", response.text)

By the code print(access_token) I can get the token string so I think I do it right on get a token. But I got 401 response when calling SharePoint API.

Status Code: 401 Response: {"error_description":"ID3035: The request was not valid or is malformed."}

What could be the problem? Thanks for your advice.

Upvotes: 1

Views: 1395

Answers (1)

Sridevi
Sridevi

Reputation: 22552

I registered one Entra ID application and granted API permissions as below:

enter image description here

Initially, I got same error when I ran your python code in my environment like this:

import requests
from msal import ConfidentialClientApplication

client_id = "xxxxxxxxxxxxxxxxxxxxx"
client_secret = "yyyyyyyyyyyyyyyyyyyyy"
tenant_id = "tttttttttttttttttttttttttttttttttttttttt"
site_url = "https://{mytenent}.sharepoint.com/sites/mysite"
resource = "https://{mytenent}"

# Authenticate using client ID and secret
authority = f"https://login.microsoftonline.com/{tenant_id}"
app = ConfidentialClientApplication(
    client_id=client_id,
    authority=authority,
    client_credential=client_secret,
)

scope=[resource + "/.default"]
token_response = app.acquire_token_for_client(scopes=scope)


access_token = token_response.get("access_token") #token_response["access_token"]
print(access_token)

endpoint_url = f"{site_url}/_api/web"
headers = {
    "Authorization": "Bearer " + access_token,
    "Accept": "application/json;odata=verbose",
    "Content-Type": "application/json;odata=verbose",
}
print(endpoint_url)
response = requests.get(endpoint_url, headers=headers)

# Check for errors in the SharePoint API response
if response.status_code == 200:
    data = response.json()
    print("SharePoint Site Title:", data["d"]["Title"])
else:
    print("SharePoint API Error:")
    print("Status Code:", response.status_code)
    print("Response:", response.text)

Response:

enter image description here

To resolve the error, you can switch to delegated flows like interactive flow, authorization code flow etc.. for generating token as you granted permissions of Delegated type.

In my case, I ran below modified code that uses interactive flow for generating token and got response successfully like this:

import requests
import msal

client_id = "appId"
tenant_id = "tenantId"
site_url = "https://tenant.sharepoint.com/sites/sridemosite"
resource = "https://tenant.sharepoint.com"

# Authenticate using client ID and secret
authority = f"https://login.microsoftonline.com/{tenant_id}"

app = msal.PublicClientApplication(
    client_id,
    authority=authority,
)
scope=[resource + "/.default"]
token_response = app.acquire_token_interactive(scopes=scope)
access_token = token_response['access_token']
print(access_token)

endpoint_url = f"{site_url}/_api/web"
headers = {
    "Authorization": "Bearer " + access_token,
    "Accept": "application/json;odata=verbose",
    "Content-Type": "application/json;odata=verbose",
}
print()
print(endpoint_url)
response = requests.get(endpoint_url, headers=headers)

# Check for errors in the SharePoint API response
if response.status_code == 200:
    data = response.json()
    print("SharePoint Site Title:", data["d"]["Title"])
else:
    print("SharePoint API Error:")
    print("Status Code:", response.status_code)
    print("Response:", response.text)

Response:

enter image description here

Make sure to enable public client flow and add redirect URI in Mobile and desktop applications platform while using interactive flow:

enter image description here

Alternatively, you can also generate access token using client certificate by granting permissions of Application type, refer below blog:

Getting an App Only access token for SharePoint REST APIs by Martin Loitzl

Upvotes: 1

Related Questions