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

如何在客户端正确存储包含刷新令牌的httponly类型Cookie?

核心误解澄清

你对逻辑的判断是正确的,你看到的所谓「刷新令牌同时存HttpOnly Cookie和localStorage」的说法本身就是错误的,二者是完全独立的两种刷新令牌存储方案,适用场景不同,从来不会同时使用:

  • HttpOnly Cookie方案的核心优势就是完全禁止前端JavaScript读写,从根源上避免XSS攻击窃取令牌,既然JS无法读取Cookie值,自然不可能把它存到localStorage里,不存在这种操作逻辑。
  • 提到localStorage的方案是另一种不依赖Cookie的实现:服务端不通过Set-Cookie头返回刷新令牌,而是把刷新令牌放在响应Body中返回给前端,前端JS拿到后自行存储到localStorage或sessionStorage中,这种方案的风险是如果站点存在XSS漏洞,攻击者可以直接读取到存储的刷新令牌。
Doorkeeper对应的两种实现配置

1. HttpOnly Cookie方案(推荐用于Web端)

配置Doorkeeper返回令牌时,额外通过Set-Cookie响应头设置带安全属性的刷新令牌Cookie,示例配置可以参考:

Doorkeeper.configure do
  after_successful_token_issuance do |token, context|
    next unless token.refresh_token
    # 设置HttpOnly刷新令牌Cookie
    context.response.set_cookie(
      :refresh_token,
      value: token.refresh_token,
      httponly: true,
      secure: Rails.env.production?,
      same_site: :lax,
      path: '/oauth/token',
      expires: token.refresh_token_expires_at
    )
    # 响应Body中移除refresh_token字段,避免前端获取冗余数据
    resp_body = JSON.parse(context.response.body)
    resp_body.delete('refresh_token')
    context.response.body = resp_body.to_json
  end
end

后续前端调用刷新令牌接口时,浏览器会自动携带该Cookie,不需要JS做任何操作,也无法读取到Cookie的具体内容。

2. localStorage存储方案(多用于跨域不便使用Cookie的场景)

保持Doorkeeper默认配置即可,刷新令牌会和访问令牌一起放在响应Body里返回,前端JS拿到后直接存储:

// 登录/获取令牌接口请求成功后
const { access_token, refresh_token, expires_in } = await tokenResp.json()
// 存入localStorage
localStorage.setItem('refresh_token', refresh_token)
// 后续刷新令牌时主动取出放在请求参数里

这种方案需要做好站点的XSS防护,避免令牌被窃取。

常见混淆点说明

很多技术帖子把两种方案混在一起提及,才会让你产生「需要同时存到两个位置」的误解,实际生产环境只需要二选一:Web端优先用HttpOnly Cookie方案,完全不需要操作localStorage;如果确实存在跨域等无法使用Cookie的场景,再用localStorage存储方案,这种场景下也不需要设置HttpOnly Cookie。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 03:45:03