AzureAD OIDC v1端点返回非JWT格式access_token无法调用Graph问题
问题分析与解决方案
为什么v1端点返回的access_token无法调用Microsoft Graph?
核心问题是v1 OAuth2端点返回的令牌类型与Microsoft Graph的要求不匹配:
- v1端点默认返回的是资源型令牌(非JWT格式),这类令牌是针对旧版Azure AD Graph设计的,而非新版Microsoft Graph。Microsoft Graph仅接受符合OIDC标准的JWT格式令牌(v2端点默认返回)。
- 你在v1流程中使用了v2风格的
scopes=["User.Read"]参数,这不符合v1端点的权限模型——v1采用resource参数指定目标服务(比如https://graph.microsoft.com),而非细粒度的scope格式。错误的参数导致端点返回了不兼容的令牌。
可行解决方案
方案1:修正v1端点的请求参数,获取兼容Graph的令牌
如果坚持使用v1端点强制MFA,可调整代码改用v1的resource参数替代scopes:
msal_app = ConfidentialClientApplication( client_id="xxx", client_credential="yyy", oidc_authority="https://sts.windows.net/{tenant}", # 保持v1端点 ) # 初始化授权码流时,用resource参数指定Graph服务 flow = msal_app.initiate_auth_code_flow( scopes=[], # v1不需要scopes,留空 redirect_uri="zzz", resource="https://graph.microsoft.com", # 指定Graph为目标资源 ) # 跳转时追加amr_values参数强制MFA auth_url = flow["auth_uri"] + "&amr_values=ngcmfa" # 获取令牌后调用Graph payload = msal_app.acquire_token_by_auth_code_flow(flow, dict(request.query_params)) response = requests.get( "https://graph.microsoft.com/v1.0/me", headers={"Authorization": f"Bearer {payload['access_token']}"} ).json()
调整后v1端点会返回针对Microsoft Graph的有效令牌,同时保留amr_values强制MFA的能力。
方案2:改用v2端点+Azure AD条件访问策略强制MFA(推荐)
amr_values是v1专属参数,v2端点不支持,但可以通过Azure AD条件访问策略更可靠地实现强制MFA:
- 在Azure门户创建条件访问策略,针对你的应用和用户群体,设置“需要多重身份验证”的访问控制。
- 切换回v2端点,正常使用MSAL的v2流程:
msal_app = ConfidentialClientApplication( client_id="xxx", client_credential="yyy", oidc_authority="https://login.microsoftonline.com/{tenant}/v2.0", # v2端点 ) flow = msal_app.initiate_auth_code_flow( scopes=["User.Read"], redirect_uri="zzz", ) # 直接跳转flow["auth_uri"],条件访问会自动触发MFA payload = msal_app.acquire_token_by_auth_code_flow(flow, dict(request.query_params)) # 正常调用Graph response = requests.get( "https://graph.microsoft.com/v1.0/me", headers={"Authorization": f"Bearer {payload['access_token']}"} ).json()
这种方式符合现代Azure AD最佳实践,MFA规则由管理员统一管控,比客户端参数强制更安全可靠。
内容的提问来源于stack exchange,提问作者edoedoedo
相关产品推荐
相关产品推荐

