Azure on_behalf_of流报错AADSTS50013:签名验证失败(密钥未找到)
问题分析与解决办法
核心错误1:On-Behalf-Of流程参数完全误用
你在第4步的请求里存在两个致命参数错误:
client_assertion参数滥用:你将client_credentials流获取的访问令牌填到了这里,但client_assertion的正确值应该是用应用私钥签名的客户端身份断言JWT,而非client_credentials令牌——后者是用来调用API的,不能作为客户端身份验证的凭证。assertion参数错误:On-Behalf-Of(OBO)流程中,assertion必须是上游客户端获取的、代表终端用户身份的访问令牌,不是你自行签名的自定义JWT。Azure AD无法识别你当前生成的自定义断言的身份和签名规则,自然会触发密钥验证失败。
核心错误2:Azure应用证书配置不完整
你的keyCredentials配置存在关键缺失:
key字段为null是无效的,Azure AD需要完整的X509证书内容(不是单独的公钥)来验证签名。你需要将生成的cert.pem文件去掉-----BEGIN CERTIFICATE-----和-----END CERTIFICATE-----头尾,把剩余的base64字符串填入key字段。customKeyIdentifier需设置为证书的SHA-1哈希值(base64编码),可通过以下OpenSSL命令生成:openssl x509 -in cert.pem -fingerprint -noout | sed 's/SHA1 Fingerprint=//g' | sed 's/://g' | xxd -r -p | base64- 配置完成后,等待5-10分钟让Azure同步配置,再查看发现端点即可看到证书信息。
修正后的OBO请求流程
- 生成合规的客户端断言JWT:用你的Java签名代码生成符合要求的客户端断言,JWT的Payload必须包含以下字段:
确保JWT头中的{ "aud": "https://login.microsoftonline.com/my-app-tenant-id/oauth2/v2.0/token", "iss": "你的客户端ID", "sub": "你的客户端ID", "exp": 1727338674, // 必须为当前时间+3600秒以内的时间戳 "iat": 1727252274 // 当前时间戳 }kid和Azure应用keyCredentials.keyId完全一致,算法为RS256。 - 获取用户访问令牌:从上游客户端获取代表终端用户的访问令牌(比如用户通过授权码流获取的JWT)。
- 发起正确的OBO请求:
POST https://login.microsoftonline.com/my-app-tenant-id/oauth2/v2.0/token Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer &client_id=你的客户端ID &client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer &client_assertion=你的客户端断言JWT &assertion=终端用户的访问令牌 &requested_token_use=on_behalf_of &scope=api://你的客户端ID/.default
额外验证要点
- 用本地JWT解码工具解析你生成的客户端断言,确认头中的
kid与Azure配置的keyId完全匹配,算法为RS256。 - 检查Azure应用的API权限,确保已添加
user_impersonation权限并完成管理员同意(若涉及企业级权限)。
内容的提问来源于stack exchange,提问作者Sergey Tsypanov
相关产品推荐
相关产品推荐

