You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 04:51:00