OAuth 2.1 几种授权流程,一次性讲清

OAuth 相关概念很多,但团队里真正高频、也最容易混淆的,其实就是几条核心流程。把它们放到同一张图景里看,选型、边界和实现位置都会清晰很多。

先说结论

先把结论放前面:

  1. 面向用户登录的主流程,默认选 authorization_code + PKCE
  2. 面向机器调用的主流程,默认选 client_credentials
  3. 受限输入设备选 device_authorization
  4. refresh_token 不是初始授权流程,而是已有授权结果的续期机制。
  5. implicitresource owner password credentials 不应该再作为新系统方案。

还有一条经常会被混到一起:

  • token_exchange 很常见,但它不是 OAuth 2.1 的核心主流程,而是 RFC 8693 定义的扩展能力,适合网关、代理和服务间换票。

OAuth 2.1 到底是什么

截至 2026 年 5 月 18 日,IETF Datatracker 上的 OAuth 2.1 仍是 Internet-Draft draft-ietf-oauth-v2-1-15,发布时间是 2026 年 3 月 2 日。它的方向不是“发明一套全新协议”,而是把 OAuth 2.0 这些年已经被业界验证过的安全实践收敛成默认基线。

可以把它理解成两件事:

  • 保留真正还值得用的流程
  • 把过去那些容易泄漏 token、边界含混、实现成本高且经常做错的模式移除或弱化

配套的安全背景,建议同时看 OAuth Security BCP,也就是 RFC 9700。这份 BCP 明确总结了哪些模式已经不适合继续推广。

oauth2-1-overview-zh@2x

先用这张图建立整体心智模型:

  • 有用户,且能正常走浏览器:authorization_code + PKCE
  • 有用户,但终端不方便登录:device_authorization
  • 没有用户,纯服务自己干活:client_credentials
  • 已经拿到授权结果,要续期:refresh_token
  • 已经有一个可信 token,想换成另一个 audience 的 token:token_exchange

1. Authorization Code + PKCE

auth-code-pkce-zh@2x

这是现在最应该优先掌握的流程,也是大多数用户登录型系统的默认答案。

适用场景

  • Web 应用
  • 单页应用(SPA)
  • 移动端 App
  • 桌面客户端

核心过程

  1. 客户端把用户导到授权服务器。
  2. 客户端发起 /authorize 请求,携带 code_challengestatescope 等参数。
  3. 用户在授权服务器侧完成登录和授权确认。
  4. 授权服务器通过重定向把 authorization code 发回客户端。
  5. 客户端再走后端通道请求 /token,提交 code + code_verifier
  6. 授权服务器校验通过后,返回 access_token,可选返回 refresh_tokenid_token

为什么 PKCE 现在是默认项

因为授权码本身不能再被当作“只要截到就能换 token”的东西。
PKCE 的本质是:

  • 前面发起授权请求时先承诺一个 challenge
  • 真正换 token 时再拿出原始 verifier

这样即使授权码在重定向链路里被截获,攻击者也无法仅凭授权码完成换 token。

安全重点

  • redirect_uri 精确匹配
  • state 防 CSRF 和混淆
  • PKCE 必开
  • token 只从后端通道返回,不走浏览器 URL
  • refresh_token 尽量做轮换

2. Client Credentials

client-credentials-zh@2x

这是最容易被误用的一种流程。它的本意非常简单:客户端代表自己,不代表某个用户

适用场景

  • 定时任务
  • 服务治理组件
  • 后台控制面
  • 内部服务调用受保护 API

核心过程

  1. 服务自己调用 /token
  2. grant_type=client_credentials
  3. 通过 client_secretprivate_key_jwt、mTLS 等方式完成客户端认证。
  4. 授权服务器返回 access_token
  5. 服务用这个 token 调下游 API。

常见误用

  • 用它替代用户授权
  • 给太宽的 scope
  • 把长期 token 当成静态密钥使用

实践重点

  • 尽量缩 scope
  • 尽量缩 audience
  • TTL 不要过长
  • 尽量提升 client authentication 强度

3. Device Authorization Grant

oauth2-1-overview-zh@2x

这是设备码流程,适合输入能力差、但又确实存在用户授权动作的终端。

适用场景

  • TV
  • 机顶盒
  • 命令行工具
  • 智能屏
  • 终端设备

核心过程

  1. 设备先向授权服务器申请 device_codeuser_code
  2. 授权服务器返回 verification_uriuser_code、轮询间隔等信息。
  3. 设备把 user_code 和访问地址展示给用户。
  4. 用户在另一台更适合登录的浏览器里打开验证页,输入 user_code,完成登录和批准。
  5. 设备按约定频率轮询 /token
  6. 在用户完成批准前,设备会收到 authorization_pending
  7. 批准后,设备才拿到 access_token,可选拿到 refresh_token

这条流程的关键点

用户认证和设备取 token 是两条链路:

  • 用户认证发生在可信浏览器
  • 设备只负责拿码、展示码、轮询 token

这也是为什么 CLI、TV 这类终端能安全接入统一登录体系。

安全重点

  • device_codeuser_code 的熵要足够
  • user_code 过期和终态要明确
  • 轮询间隔要受控,过快要返回 slow_down
  • 批准动作必须和登录态、上下文、设备请求绑定

4. Refresh Token

refresh-token-zh@2x

严格说,refresh_token 不是一条“第一次拿授权”的主流程,而是一条“已有授权结果后的续期链路”。

它解决的矛盾

访问令牌应该短寿命,否则泄漏窗口太大。
但如果 access token 太短,用户每几分钟重新登录一次也不可接受。

所以典型做法是:

  • access token 短 TTL
  • refresh token 用来换新的 access token

核心过程

  1. 客户端发现 access token 过期或即将过期。
  2. 客户端调用 /tokengrant_type=refresh_token
  3. 授权服务器校验 refresh token 和客户端归属。
  4. 返回新的 access token。
  5. 更稳妥的做法是同时返回新的 refresh token,也就是 refresh token rotation。

安全重点

  • refresh token 只发给真正需要续期能力的客户端
  • refresh token 不应该暴露给资源服务器
  • 建议做轮换
  • 建议做撤销与异常检测

5. Token Exchange

token-exchange-zh@2x

这条流程经常出现在企业网关、代理层和服务网格里,但它不是 OAuth 2.1 主体的一部分,而是 RFC 8693 定义的扩展。

它要解决什么

现实系统里,一个服务常常已经拿到某个“上游可信 token”,但这个 token:

  • audience 不对
  • scope 太大
  • 来源域不一致
  • 不适合直接给下游继续用

这时就会做 token exchange:

  • 拿一个已有 token 或主体断言
  • 去授权服务器换一张新的、面向特定 audience 的 token

典型场景

  • API Gateway 用用户登录态换内部服务 token
  • Service A 拿到外部 IdP token,再换成内部域 token
  • BFF 或代理层把用户 token 换成下游专用 token

安全重点

  • 明确 subject_token 的来源和可信边界
  • 明确新 token 的 audience
  • 明确缩 scope,而不是原样放大复制
  • 明确谁有资格做 exchange

为什么 Implicit 和 Password 不再推荐

Implicit Grant

implicit 的问题不是“完全不能实现”,而是它把 access token 暴露在前端重定向链路里,带来更多泄漏面,例如:

  • 浏览器历史
  • 地址栏
  • 前端日志
  • 引用头(Referer)
  • 各种第三方脚本和中间跳转

现在 authorization_code + PKCE 已经可以覆盖浏览器类客户端,就没有必要继续推广 implicit。

Resource Owner Password Credentials

password 模式的问题更根本:客户端自己向用户要密码。
这会直接破坏 OAuth 里最重要的一层边界:

  • 用户不再只把凭据交给授权服务器
  • 客户端本身变成了密码采集点
  • 上游登录策略、MFA、风控、凭据演进都更难统一

所以今天讨论新系统,默认就不应再把它当候选项。

参考资料

posted @ 2026-05-18 23:13  JMCui  阅读(153)  评论(0)    收藏  举报