We have a Python code that tries to query an API deployed on Microsoft Azure. The Code first requests an access token from the API using azure-identity
library and then sends the token in the Authorization
header of the request like the following:
import requests
from azure.identity import ClientSecretCredential
TENANT_ID = 'my-tenant-id'
CLIENT_ID = 'my-client-id'
CLIENT_SECRET = "my_client-secret"
SCOPES = ['api://my-client-id/.default']
identity_client = ClientSecretCredential(tenant_id=TENANT_ID,
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
authority='https://login.microsoftonline.com')
access_token = identity_client.get_token(SCOPES[0])
#Request the API endpoint
json = {
"function_name": "function_name",
"param1": "param1_value",
"param2": "param2_value",
}
headers = {
"Authorization": f"Bearer {access_token.token}",
"Content-Type": "application/json"
}
response = requests.get('https://myapi.whatever/myendpoint',
json=json, headers=headers)
if response.status_code == 200:
print(response.json()["result"])
else:
print(response)
However, also we get an access token (with valid signature on jwt.io
); we get the following error/response when we query the endpoint:
{'_content': b'missing_claim',
'_content_consumed': True,
'_next': None,
'status_code': 401,
'headers': {'Date': 'Fri, 12 May 2023 15:25:27 GMT', 'Content-Type': 'text/plain', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Request-Context': 'appId=cid-v1:752b04bc-08aa-4002-a618-d3e7be07a371', 'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'sameorigin', 'X-Permitted-Cross-Domain-Policies': 'none', 'Referrer-Policy': 'no-referrer'},
'raw': <urllib3.response.HTTPResponse at 0x2967109e3a0>,
'url': 'https://myapi.whatever/myendpoint',
'encoding': 'ISO-8859-1',
'history': [],
'reason': 'Unauthorized',
'cookies': <RequestsCookieJar[]>,
'elapsed': datetime.timedelta(microseconds=306335),
'request': <PreparedRequest [GET]>,
'connection': <requests.adapters.HTTPAdapter at 0x296710856a0>}
I am not sure what is causing this also we configured the permissions for the API correctly… could anyone have any idea of what is causing this error and how to fix it? Thanks.
Also note that we tried using other libraries like msal
for example:
app = msal.ConfidentialClientApplication(
client_id=CLIENT_ID,
client_credential=[CLIENT_SECRET],
authority='https://login.microsoftonline.com/my-tenant-id',
token_cache=cache,
)
result = None
result = app.acquire_token_silent(scopes=SCOPES, account=None)
if not result:
print('Here')
result = app.acquire_token_for_client(scopes=SCOPES)
but still the same error…
2
Answers
I agree with @Gaurav Mantri, the error
401 Unauthorized
usually occurs if your service principal does not have permissions to call the API.To confirm that, decode the access token and check whether it has
scp
claim with API permission or not.If you added scope in
Expose an API
tab, it creates delegated permissions like below:I generated access token using client credentials flow via Postman like this:
Response:
When I used above access token to call API, I too got
401 Unauthorized
error like below:Response:
To resolve the error, you have to use delegated flow like authorization code flow, interactive flow or username password flow etc…
In my case, I generated access token using authorization code flow via Postman like this:
Response:
When I decoded this token in jwt.ms, it has
scp
claim with API permission like below:I can make API call successfully with above access token like this:
Response:
You can check this SO thread to generate access token using auth code flow via Python.
I wanted to ask what is the scope of the token generated by the first method, where can we use that token?