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

React公共客户端用Keycloak刷新令牌时遇“Session doesn't have required client”错误

问题描述

React Vite(React + TS v5.3.1)项目对接Docker部署的Keycloak v25.0.1,需实现OAuth2的授权码流程与刷新令牌流程。授权码流程可正常获取access_token、refresh_token、id_token,但调用Keycloak的/token端点发送包含grant_type=refresh_token、client_id、refresh_token参数的POST请求刷新令牌时,返回错误:

{
    "error": "invalid_grant",
    "error_description": "Session doesn't have required client"
}

当前Keycloak配置:

  • 禁用Revoke Refresh Token
  • 仅启用Standard Flow
  • 开启Use Refresh Token

相关代码:
Docker启动Keycloak命令:

# 运行默认Keycloak实例
docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak start-dev

React中获取令牌的代码:

const navigate = useNavigate();

useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const authZCode = params.get("code");

    const fetchDataToLS = async (codeHere: string) => {
        const tokenRes = await axios.post<TKCTokenResponse>(
            import.meta.env.VITE_KC_SERVER_TOKEN,
            new URLSearchParams({
                client_id: "myclient",
                code: codeHere,
                grant_type: "authorization_code",
            })
        );

        const { access_token, refresh_token, id_token } = tokenRes.data;
        localStorage.setItem("access_token", access_token);
        localStorage.setItem("refresh_token", refresh_token);
        localStorage.setItem("id_token", id_token);
        navigate("/protected");
    };

    fetchDataToLS(authZCode!);
    callTime++;
}, [callTime, navigate]);
排查与解决方案

1. 补全刷新请求的必要参数

刷新令牌请求必须包含完整的合规参数,缺失或错误会触发会话验证失败:

  • 必须携带grant_type=refresh_token、client_id、refresh_token
  • 若客户端配置为confidential类型,需额外添加client_secret参数
  • 若授权码请求时指定了scope,刷新时需携带相同的scope

示例正确的刷新请求代码:

const refreshToken = async () => {
  const refreshTokenVal = localStorage.getItem("refresh_token");
  try {
    const res = await axios.post(
      import.meta.env.VITE_KC_SERVER_TOKEN,
      new URLSearchParams({
        client_id: "myclient",
        grant_type: "refresh_token",
        refresh_token: refreshTokenVal!,
        // 若客户端为confidential类型,取消注释此行
        // client_secret: "your-client-secret",
        // 若授权时指定了scope,取消注释此行
        // scope: "openid email profile"
      })
    );
    // 用新令牌替换本地存储的旧值
    localStorage.setItem("access_token", res.data.access_token);
    localStorage.setItem("refresh_token", res.data.refresh_token);
  } catch (err) {
    console.error("刷新令牌失败:", err);
  }
};

2. 修正Keycloak客户端配置

  • Access Type设置:前端React应用需将客户端的Access Type设为public,若误设为confidential,刷新时必须携带client_secret,否则会触发会话绑定错误。
  • Valid Redirect URIs:确认该配置包含当前应用的完整域名,确保授权会话与应用域名绑定。
  • Use Refresh Token:再次检查Keycloak后台客户端设置,确认该选项已开启。

3. 排查会话绑定异常

Keycloak的刷新令牌与用户会话、客户端强绑定,以下情况会导致错误:

  • 刷新令牌对应的用户会话已过期或被注销:可在Keycloak后台「用户>会话」页面查看会话状态。
  • 旧刷新令牌被重复使用:Keycloak默认在刷新后失效旧的refresh_token,需确保每次刷新后用新返回的refresh_token替换本地存储的值。
  • 客户端ID不一致:刷新请求的client_id必须与授权码请求的完全一致。

4. 确保请求符合规范

Keycloak v25.0.1对OAuth2流程验证逻辑有更新,需保证:

  • 请求的Content-Type必须为application/x-www-form-urlencoded(代码中使用URLSearchParams已满足,但需确认axios未自动修改该头部)。
  • 若授权码请求时指定了redirect_uri,刷新请求可尝试携带相同的redirect_uri参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 00:40:08