从Azure AD获取Token遇AADSTS50148错误:PKCE的code_verifier不匹配
Azure AD OAuth2授权码模式获取Token时AADSTS50148错误解决
问题描述
已完成Azure登录授权弹窗流程并获取到授权code,但调用token接口时返回如下错误:
{ "correlation_id": "94961159-xxxx-xxxx-xxxx-0c400f7d11e8", "error": "invalid_grant", "error_codes": [50148], "error_description": "AADSTS50148: The code_verifier does not match the code_challenge supplied in the authorization request for PKCE.", "error_uri": "https://login.microsoftonline.com/error?code=50148", "timestamp": "2022-07-21 05:25:40Z", "trace_id": "dc2ba549-909b-4446-8bb7-8f961e9ba600" }
当前用于请求token的代码如下:
var requestParams: any = { client_id: "0b585496-xxxx-xxxx-xxxx-c0468796e718", scope: "User.Read", code: props.code, // 来自授权返回的code redirect_uri: "myapp://login", grant_type: "authorization_code", }; var formBody: any = []; for (var p in requestParams) { var encodedKey = encodeURIComponent(p); var encodedValue = encodeURIComponent(requestParams[p]); formBody.push(encodedKey + "=" + encodedValue); } formBody = formBody.join("&"); let tokenResponse: any = null; fetch( `https://login.microsoftonline.com/afdb7f3a-xxxx-xxxx-xxxx-4d604512e9f0/oauth2/v2.0/token`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", }, body: formBody, } ) .then((response) => response.json()) .then((response) => { tokenResponse = response; console.log(response); }) .catch((error) => { console.error(error); });
错误原因
你的应用在发起授权请求时使用了PKCE(Proof Key for Code Exchange)安全流程,但在获取token的请求中缺少了对应的code_verifier参数,或者该参数的值与授权请求阶段生成的code_challenge不匹配。
PKCE流程要求:
- 授权请求前生成一个随机的
code_verifier字符串(长度43-128位,包含字母、数字、-、.、_、~) - 将
code_verifier通过SHA256哈希后再Base64URL编码,得到code_challenge,随授权请求发送给Azure AD - 获取token时,必须携带原始的
code_verifier,Azure AD会验证其与之前的code_challenge是否匹配,以此防止授权code被劫持
修复方案
- 找到授权请求阶段生成的
code_verifier值(如果是自行实现的授权请求,需保留该值;如果使用SDK,需确保将其传递到token请求中) - 在请求token的参数里添加
code_verifier字段,值为授权阶段生成的原始字符串 - 确保
code_verifier没有被错误编码,代码中已对所有参数做encodeURIComponent处理,直接传入原始值即可
修改后的代码示例
var requestParams: any = { client_id: "0b585496-xxxx-xxxx-xxxx-c0468796e718", scope: "User.Read", code: props.code, // 来自授权返回的code redirect_uri: "myapp://login", grant_type: "authorization_code", code_verifier: "你的授权阶段生成的code_verifier值" // 添加该参数 }; var formBody: any = []; for (var p in requestParams) { var encodedKey = encodeURIComponent(p); var encodedValue = encodeURIComponent(requestParams[p]); formBody.push(encodedKey + "=" + encodedValue); } formBody = formBody.join("&"); let tokenResponse: any = null; fetch( `https://login.microsoftonline.com/afdb7f3a-xxxx-xxxx-xxxx-4d604512e9f0/oauth2/v2.0/token`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", }, body: formBody, } ) .then((response) => response.json()) .then((response) => { tokenResponse = response; console.log(response); }) .catch((error) => { console.error(error); });
内容的提问来源于stack exchange,提问作者Haksatrya Bhaswara
相关产品推荐
相关产品推荐

