使用Python获取Microsoft Graph API Access Token遇授权码失效及MFA问题
解决Microsoft Graph授权码重复使用错误及无Refresh Token动态获取Access Token方法
问题描述
我尝试复刻网页版Microsoft Graph Explorer获取Access Token的流程,将抓包请求转为Python代码后运行报错,错误信息如下:
b'{"error":"invalid_grant","error_description":"AADSTS54005: OAuth2 Authorization code was already redeemed, please retry with a new valid code or use an existing refresh token.`
我的账号开启了MFA,需通过Microsoft Authenticator输入验证数字完成授权,且没有client secret,想了解无需refresh token动态获取Access Token的方法。
附尝试的Python代码:
import requests headers = { 'Accept': '*/*', 'Accept-Language': 'en-GB,en;q=0.9', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive', 'Origin': 'https://developer.microsoft.com', 'Pragma': 'no-cache', 'Referer': 'https://developer.microsoft.com/', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'cross-site', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36', 'content-type': 'application/x-www-form-urlencoded;charset=utf-8', 'sec-ch-ua': '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', } data = 'client_id=de8bc8b5-d9f9-48b1-a8ad-b748da725064&redirect_uri=https%3A%2F%2Fdeveloper.microsoft.com%2Fen-us%2Fgraph%2Fgraph-explorer&scope=openid%20profile%20User.Read%20offline_access&code=vW3k&x-client-SKU=msal.js.browser&x-client-VER=3.10.0&x-ms-lib-capability=retry-after, h429&x-client-current-telemetry=5|862,0,,,|,&x-client-last-telemetry=5|0|862,018f6224-a10e-73ae-b32d-a10aeab7b49b|user_cancelled|1,0&code_verifier=zpUdixfdLj4CsnhptxSZio&grant_type=authorization_code&client_info=1&client-request-id=018f6226-77e8-9028-ae2685da3b62&claims=%7B%22access_token%22%3A%7B%22xms_cc%22%3A%7B%22values%22%3A%5B%22CP1%22%5D%7D%7D%7D&X-AnchorMailbox=Oid%3A7aed27cb-3dd1-45d8-8323-7d0387be5ce0%4057c64fd4-66ca-49f5-ab38-2e67ef58e724' response = requests.post('https://login.microsoftonline.com/common/oauth2/v2.0/token', headers=headers, data=data)
请求payload:
client_id: de8bc8b5-d9f9-48b1-a8ad-b748da725064 redirect_uri: https://developer.microsoft.com/en-us/graph/graph-explorer scope: openid profile User.Read offline_access code: 0.AQYA1E_GV8pm9UmrOC5n71jnJLXIi9752bFIqK23SNpyUGQGAMQ.xxxx x-client-SKU: msal.js.browser x-client-VER: 3.10.0 x-ms-lib-capability: retry-after, h429 x-client-current-telemetry: 5|862,0,,,|, x-client-last-telemetry: 5|0|862,018f6224-xxxx-xxxx-b32d-a10aeab7b49b|user_cancelled|1,0 code_verifier: zpUdixfdLxhmpxxxx grant_type: authorization_code client_info: 1 client-request-id: 018f6226-xxx-xxx-xxx-ae2685da3b62 claims: {"access_token":{"xms_cc":{"values":["CP1"]}}} X-AnchorMailbox: Oid:7aed27cb-xxx-xxx-8323-7d0387be5ce0@57c64fd4-66ca-xxxx-xxxx-2e67ef58e724
错误原因
- OAuth2的授权码(authorization code)是一次性凭证,你抓包获取的code已经被网页版Graph Explorer使用过,再次提交自然触发AADSTS54005错误。
- 直接复用抓包的请求参数(如code_verifier、client-request-id)不符合授权流程规范,每个授权会话都需要生成独立的code challenge/verifier对。
解决方案:用MSAL Python实现带MFA的授权码流程
无需client secret,每次通过完整授权流程获取新的Access Token,避免依赖refresh token。
步骤1:安装MSAL库
pip install msal
步骤2:编写Python代码
import msal import webbrowser from urllib.parse import urlparse, parse_qs # 配置参数,和Graph Explorer保持一致 CLIENT_ID = "de8bc8b5-d9f9-48b1-a8ad-b748da725064" REDIRECT_URI = "https://developer.microsoft.com/en-us/graph/graph-explorer" SCOPE = ["openid", "profile", "User.Read", "offline_access"] # 初始化公共客户端应用 app = msal.PublicClientApplication(CLIENT_ID, authority="https://login.microsoftonline.com/common") # 生成授权流程,包含唯一的code verifier和授权URL flow = app.initiate_auth_code_flow(scopes=SCOPE, redirect_uri=REDIRECT_URI) # 打开浏览器引导用户完成授权(含MFA验证) webbrowser.open(flow["auth_uri"]) # 提示用户输入授权后的回调URL print("完成浏览器中的MFA验证后,复制地址栏的完整URL粘贴到这里:") callback_url = input().strip() # 解析回调URL中的授权码 parsed_url = urlparse(callback_url) auth_code = parse_qs(parsed_url.query)["code"][0] # 用授权码和code verifier获取Access Token result = app.acquire_token_by_auth_code_flow(flow, callback_url) # 输出结果 if "access_token" in result: print("成功获取Access Token:") print(result["access_token"]) else: print(f"获取失败:{result.get('error')} - {result.get('error_description')}")
方法优势
- 每次运行生成全新授权会话,彻底避免授权码重复使用问题
- 自动适配MFA验证,用户仅需在浏览器中完成Microsoft Authenticator的验证步骤
- 符合公共客户端(无client secret)的OAuth2规范
- 无需依赖refresh token,每次都通过完整流程获取有效Access Token
内容的提问来源于stack exchange,提问作者Drew
相关产品推荐
相关产品推荐

