JWT验证失败:无https://sts.windows.net/{tenant}签发者问题求助
调用自定义SPARQL API时返回401状态码,服务器日志提示:
Failed verify the JWT: There is no issuer named https://sts.windows.net/{{TENANT_ID}} Header token API authorization failed: Authentication failed for account 'bearer'
已将应用注册的accessTokenAcceptedVersion设置为2,超过24小时问题仍存在,原代码示例如下:
import requests from msal import ConfidentialClientApplication clientId = "{{CLIENT_ID}}" tenantId = "{{TENANT_ID}}" clientSecret = "{{CLIENT_SECRET}}" endpoint = "https://sparql..profile2.sd-testlab.com" authority = f"https://login.microsoftonline.com/%7BtenantId%7D" app = ConfidentialClientApplication( client_id=clientId, client_credential=clientSecret, authority=authority ) s = ["https://graph.microsoft.com/.default"] result = app.acquire_token_for_client(scopes=s) if "access_token" not in result: print(result.get("error")) print(result.get("error_description")) print(result.get("correlation_id")) # You may need this when reporting a bug header = {"Authorization": "Bearer " + result["access_token"]} r = requests.get(url=f'{endpoint}/databases', headers=header) print(r)
排查与修复步骤
1. 修复Authority构造错误
原代码中authority = f"https://login.microsoftonline.com/%7BtenantId%7D"存在变量替换错误,%7B是URL编码的左大括号,会被当成字面量而非变量占位符。同时,因为已设置accessTokenAcceptedVersion=2,必须使用v2身份验证终结点,正确的Authority写法为:
authority = f"https://login.microsoftonline.com/{tenantId}/v2.0"
此修改会让生成的Token发行者(iss)变为https://login.microsoftonline.com/{tenantId}/v2.0,而非旧版的sts.windows.net格式,匹配API的验证要求。
2. 修正Scope参数
原代码使用了Graph API的Scope(https://graph.microsoft.com/.default),但调用的是自定义SPARQL API,必须使用目标API的应用ID URI加上/.default作为Scope。例如,如果目标API的应用ID URI是https://sparql.profile2.sd-testlab.com,则Scope应为:
target_api_scope = ["https://sparql.profile2.sd-testlab.com/.default"]
错误的Scope会导致Token的受众(aud)不匹配目标API,直接触发401。
3. 验证Token核心字段
获取Token后,本地解码查看iss和aud两个关键字段:
iss必须为https://login.microsoftonline.com/{你的租户ID}/v2.0aud必须是目标API的应用ID或应用ID URI
若这两个字段不符合API配置,验证必然失败。
4. 确认应用配置有效性
- 目标API的应用注册中,确保
accessTokenAcceptedVersion已设为2并保存生效,必要时重新保存应用配置。 - 客户端应用(用于获取Token的应用)已被授予目标API的应用权限(客户端凭据流仅支持应用权限),且已完成管理员同意操作。
修正后的完整代码
import requests from msal import ConfidentialClientApplication clientId = "{{CLIENT_ID}}" tenantId = "{{TENANT_ID}}" clientSecret = "{{CLIENT_SECRET}}" endpoint = "https://sparql.profile2.sd-testlab.com" # 修正原URL中的多余点 # 使用v2终结点构造Authority authority = f"https://login.microsoftonline.com/{tenantId}/v2.0" app = ConfidentialClientApplication( client_id=clientId, client_credential=clientSecret, authority=authority ) # 使用目标API的Scope target_api_scope = ["https://sparql.profile2.sd-testlab.com/.default"] result = app.acquire_token_for_client(scopes=target_api_scope) if "access_token" not in result: print(result.get("error")) print(result.get("error_description")) print(result.get("correlation_id")) else: header = {"Authorization": "Bearer " + result["access_token"]} r = requests.get(url=f'{endpoint}/databases', headers=header) print(r.status_code) print(r.text)
内容的提问来源于stack exchange,提问作者Serge Colle
相关产品推荐
相关产品推荐

