该流程为何而设

2.0(RFC 6749)让一个应用能够代表用户行事,而从不看到用户的密码。“用 Google 登录”是日常的例子:应用获得访问某物的许可,但处理凭据的是 Google,而非应用。授权码流是安排此事最常见、最安全的方式,也正是 所保护的流程。

四个角色

  • 资源所有者(resource owner)是拥有数据并授予访问权的用户。
  • 客户端(client)是请求访问的应用。
  • 授权服务器(authorization server)对用户进行认证并签发令牌(Google、一个身份提供方、你自己的认证服务)。
  • 资源服务器(resource server)是持有受保护数据并接受令牌的 API。

舞步,逐步而行

  1. 重定向去授权。 客户端把用户的浏览器送往授权服务器的授权端点,携带它的 client_id、一个 redirect_uri、它想要的 scope、一个随机的 state 值,以及(在 PKCE 下)一个码挑战。客户端从不经手密码。
  2. 认证与同意。 授权服务器让用户登录,并请其批准所请求的作用域。
  3. 带着一个码重定向回来。 服务器把浏览器重定向回客户端的 redirect_uri,带着一个短命的授权码和原始的 state。客户端核对 state 是否相符,这可在回调时防御跨站请求伪造。
  4. 用码交换令牌。 此刻在后端信道上(一次直接的服务器到服务器调用,而非浏览器),客户端把码连同其凭据(一个客户端秘密,或 PKCE 码验证者)一并发往令牌端点,并收到一个访问令牌、常常一个刷新令牌,以及对 OpenID Connect 而言一个 ID 令牌
  5. 调用 API。 客户端把访问令牌出示给资源服务器,后者将其校验并返回数据。

为何用一个码,而非直接用令牌?

绕道经过一个授权码而存在,是为了令牌永不途经浏览器的地址栏或历史,那里它可能泄露。那个确实途经那里的码,单凭自身毫无用处:兑换它需要带着客户端秘密或 PKCE 验证者的后端信道调用。那种分隔,前端信道上一个一次性的码、后端信道上真正的令牌,正是该流程的核心安全性质。

这也正是 PKCE 为那些无法保守一个秘密的客户端(单页与移动应用)所填补的缺口:它把码绑定到一个一次性验证者,于是一个被拦截的码仍无法被交换。该流程返回的令牌,很常常是

PKCE 工具 生成并核对此流程所倚赖的验证者与挑战,而 JWT 工具 解码它返回的令牌,二者皆在你的浏览器中本地进行。