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

Keycloak使用账号密码登录后如何撤销旧的refresh token?

Keycloak 新登录后撤销旧Refresh Token实现方案

基础前置配置

首先开启Refresh Token单次有效配置,满足你提到的refresh token被盗用后用户能感知的需求:

  1. 进入对应Realm的Clients页面,找到你正在使用的客户端,进入Settings标签
  2. 找到OpenID Connect Compatibility Modes模块,开启Revoke Refresh Token选项,该配置就是你提到的reuse refresh=0效果,Refresh Token使用一次后会自动失效,用过期的Refresh Token请求刷新会直接返回400错误
  3. 根据业务需求调整Access Token Lifespan、Refresh Token Lifespan的时长,建议Refresh Token最长有效期不超过7天

新密码登录自动撤销旧Refresh Token实现

方案1:内置会话并发控制(无代码侵入,推荐)

Keycloak自带会话数量限制能力,直接配置即可实现需求:

  1. 进入对应Realm的Realm Settings → Sessions标签页
  2. 将Session count limit配置为1,表示同一用户同一时间仅允许存在1个有效会话
  3. When session limit is exceeded选项选择Terminate oldest session,即新会话创建后自动终止最老的会话
  4. 保存配置后,用户每次用账号密码完成登录生成新会话时,旧会话关联的所有Refresh Token、Access Token都会被自动撤销,完全符合需求

注意:该配置为Realm全局生效,会作用于该Realm下的所有客户端,若需要仅针对单个客户端生效,可使用下方自定义SPI方案

方案2:自定义认证SPI(灵活可控)

如果需要细粒度控制(比如仅针对密码授权模式触发旧Token撤销),可以自行扩展Keycloak认证逻辑:

  1. 实现Authenticator接口,在密码认证成功的逻辑后添加如下核心代码:
// 获取当前用户所有有效会话
List<UserSessionModel> userSessions = session.sessions().getUserSessions(realm, user);
for (UserSessionModel userSession : userSessions) {
    // 跳过当前新生成的会话
    if (userSession.getId().equals(context.getAuthenticationSession().getParentSession().getId())) {
        continue;
    }
    // 移除旧会话,关联的所有Token会自动失效
    session.sessions().removeUserSession(realm, userSession);
}
  1. 将自定义SPI打包后放入Keycloak安装目录的providers文件夹,重启Keycloak生效
  2. 进入Realm的Authentication → Flows页面,找到Direct Grant(密码授权对应的认证流),将自定义的认证步骤添加到密码校验步骤之后即可

效果验证

配置完成后可按以下步骤测试是否生效:

  • 第一次用账号密码请求Token,得到refresh_token_1和access_token_1,可正常使用刷新接口获取新Token,刷新后refresh_token_1自动失效
  • 第二次用同一个账号密码请求Token,得到refresh_token_2和access_token_2
  • 用之前生成的所有旧Refresh Token请求刷新,都会返回invalid_grant错误,说明旧Token已被成功撤销

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 09:06:04