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

Spring集成Keycloak获取令牌时redirect_uri错误400问题

问题分析与解决方案

核心问题定位

报错invalid_grant: Incorrect redirect_uri的关键原因是Spring代码中传入的redirect_uri与授权请求时使用的redirect_uri不完全一致,或是代码生成的URI存在多余格式(比如带空查询参数),导致Keycloak校验不通过。

具体修复步骤

  1. 统一redirect_uri格式
    直接用字符串常量传入redirect_uri,避免UriComponentsBuilder.build()可能生成的多余格式(比如带空?后缀):

    map.add("redirect_uri", "http://127.0.0.1:3002/callback");
    
  2. 校验授权请求与回调的URI一致性
    确保用户跳转到Keycloak授权页面时携带的redirect_uri,和回调代码中传入的完全一致——包括协议、主机、端口、路径,localhost和127.0.0.1会被视为不同地址,末尾也不能多带斜杠。

  3. 验证请求参数匹配度
    在catch块中打印完整请求参数,对比Postman的参数是否完全一致:

    catch (Exception e) {
        System.out.println(e.getMessage());
        System.out.println("实际发送参数: " + map.toString());
    }
    

    重点确认client_secret为空的配置是否和Keycloak客户端类型匹配(public类型客户端无需secret)。

  4. 检查Keycloak客户端配置
    确认客户端的Valid Redirect URIs列表包含http://127.0.0.1:3002/callback,可使用通配符http://127.0.0.1:3002/*放宽匹配范围。

修复后完整代码示例

@GetMapping("/callback")
@ResponseBody
public String getToken(@RequestParam String code) {
    RestTemplate restTemplate = new RestTemplate();

    HttpHeaders headers = new HttpHeaders();
    headers.add("Content-Type", MediaType.APPLICATION_FORM_URLENCODED.toString());

    MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
    map.add("code", code);
    map.add("client_id", "spring-login-app");
    map.add("client_secret", "");
    map.add("grant_type", "authorization_code");
    map.add("redirect_uri", "http://127.0.0.1:3002/callback");

    HttpEntity formEntity = new HttpEntity<>(map, headers);
    try {
        ResponseEntity<KeycloakTokenResponse> response =
                restTemplate.exchange("http://127.0.0.1:8080/auth/realms/raroc/protocol/openid-connect/token",
                        HttpMethod.POST,
                        formEntity,
                        KeycloakTokenResponse.class);
        KeycloakTokenResponse resp = response.getBody();
        return resp.getAccess_token();
    } catch (Exception e) {
        System.out.println(e.getMessage());
        System.out.println("实际发送参数: " + map.toString());
    }

    return "nothing";
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 19:39:27