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

Spring Boot集成IdentityServer4调用/connect/token传code_verifier报invalid_grant如何解决

问题根因
  • 核心错误是将授权请求中的code_challenge直接作为code_verifier传入token接口,违反PKCE(RFC7636)规范的校验逻辑
  • 手动构造请求时未获取Spring Security OAuth2 Client自动生成的正确code_verifier
  • 存在参数配置不匹配、请求参数拼接错误的问题
解决步骤

1. 修正PKCE参数的取值逻辑

PKCE的正确生成和使用规则如下,你当前的传值逻辑完全颠倒:

  • 第一步:生成长度为43~128位的随机字符串作为原始code_verifier,允许的字符范围为A-Z/a-z/0-9/-/./_/~
  • 第二步:对code_verifier做SHA256哈希运算后,再做Base64URL编码得到code_challenge,放到/connect/authorize授权请求中
  • 第三步:调用/connect/token接口时传入原始未哈希的code_verifier,而非授权请求里的code_challenge

2. 复用Spring Security自动生成的code_verifier

Spring Security OAuth2 Client的oauth2Login流程已经自动完成了code_verifier的生成、存储和token请求校验逻辑,如果你确实需要手动调用token接口,可以从会话中取出系统生成的正确code_verifier:

import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest;
import javax.servlet.http.HttpServletRequest;

// 在需要获取参数的方法中注入HttpServletRequest对象
OAuth2AuthorizationRequest authRequest = (OAuth2AuthorizationRequest) request.getSession()
    .getAttribute(OAuth2AuthorizationRequest.class.getName() + ".AUTHORIZATION_REQUEST");
String correctCodeVerifier = (String) authRequest.getAttribute("code_verifier");

将取到的correctCodeVerifier作为code_verifier参数的值传入token请求即可。

3. 修正其他错误

  • 参数一致性:你的配置文件中client-id为client_id_test,请求中传的client_id=client_id需修改为和配置一致的值
  • 认证方法匹配:配置中client-authentication-method: none为公共客户端模式,不需要传client_secret参数,调用token接口时删除该参数即可
  • 请求格式修正:你当前的form参数拼接错误,redirect_uri参数末尾缺少&符号,会导致后续参数解析失败,需补充该符号

4. 最佳实践:直接使用Spring封装的token获取方式

完全不需要手动构造RestTemplate调用token接口,直接注入OAuth2AuthorizedClientService即可直接拿到已校验完成的access token:

import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.core.Authentication;

@Autowired
private OAuth2AuthorizedClientService authorizedClientService;

public String getAccessToken(Authentication authentication) {
    OAuth2AuthorizedClient client = authorizedClientService.loadAuthorizedClient(
        "idsrv4",
        authentication.getName()
    );
    return client.getAccessToken().getTokenValue();
}

内容的提问来源于stack exchange,提问作者user1168880

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 21:06:01