在 OAuth 2.0 + PKCE(Proof Key for Code Exchange)认证过程中,这三个参数分别承担不同的职责:
code_verifier 计算出来的摘要,发送给认证服务器。最重要的一点是:PKCE 的核心就是让客户端在申请 Token 时,证明自己持有最初生成的 code_verifier。
| 参数 | 生成方 | 生成时机 | 作用 |
|---|---|---|---|
| code_verifier | 客户端 | 发起认证之前 | 原始随机密钥 |
| code_challenge | 客户端 | 发起认证之前 | verifier 的 SHA-256 摘要 |
| code | 认证服务器 | 用户授权成功之后 | 临时授权凭证 |
由客户端生成。
例如,客户端生成一个足够长、随机且不可预测的字符串:
code_verifier = dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
这个值有几个特点:
同样由客户端生成。
客户端使用刚才的 code_verifier,通过 SHA-256 计算摘要,然后进行 Base64URL 编码:
code_challenge = BASE64URL(SHA256(code_verifier))
注意,这里通常使用 S256 模式,而不是 plain 模式。
客户端在发起授权请求时,将 code_challenge 和 code_challenge_method 直接放在 URL 里以明文方式发送给认证服务器。认证服务器必须保存 code_challenge 和 code_challenge_method
由认证服务器生成,并临时保存在内存(或者外部存储)中。这个 code 必须关联对应的 client_id 和 redirect_uri。
当用户完成登录并同意授权后,认证服务器生成一个临时授权码:
authorization_code = "SplxlOBeZQQYbYS6WxSbIA"
然后通过客户端预先指定的 Redirect URI,将这个 code (附在 Response 中以明文方式)返回给客户端。
客户端拿到 code 后,才能进入下一步 Token 交换流程。
我们把整个过程分成两个阶段:
客户端生成 code_verifier
客户端本地生成随机字符串,并保存起来。
客户端计算 code_challenge
使用 SHA-256 + Base64URL 计算摘要。
客户端向授权服务器发送授权请求
通过浏览器跳转到 Authorization Endpoint:
GET /authorize?
response_type=code&
client_id=123&
redirect_uri=...&
code_challenge=ABC...&
code_challenge_method=S256&
scope=openid
注意:这里发送的是 code_challenge,不是 code_verifier。
服务器记录 code_challenge
服务器将 code_challenge 和计算方法 code_challenge_method 与本次授权请求关联起来。
用户完成登录和授权
授权服务器生成 code。
服务器重定向回客户端
HTTP/1.1 302 Found
Location: https://client.com/callback?code=XYZ123
客户端从回调 URL 中获取 code。
客户端向 Token Endpoint 发送请求
通过 HTTP POST:
POST /token
Content-Type: application/x-www-form-urlencoded
请求参数:
grant_type=authorization_code
client_id=123
code=XYZ123
redirect_uri=...
code_verifier=dBjftJeZ4...
服务器验证 PKCE
服务器拿到 code_verifier,重新计算:
BASE64URL(SHA256(code_verifier))
然后与之前保存的 code_challenge 比较。
验证通过,返回 Token
{
"access_token": "...",
"refresh_token": "...",
"token_type": "Bearer"
}
验证失败则拒绝本次 Token 交换。
依据:RFC 7636 第 4.1~4.6 节。

假设没有 PKCE:
加入 PKCE 后:
code_verifier。这就是 PKCE 的核心安全机制:授权码本身不再足以兑换 Token,还必须提供最初生成的随机凭证。
如果你自己实现 OAuth 2.0 Authorization Server,需要注意:
code_challenge 和 code_challenge_method。code 和 code_verifier。这里有个非常重要的细节:
服务器不需要保存 code_verifier,只需要保存 code_challenge 和 code_challenge_method。
因为服务器可以在 Token 请求阶段,根据客户端传来的 verifier 重新计算 challenge。
另外,授权码应该是短期有效、一次性使用的,并且要绑定对应的客户端和 redirect_uri。
最后总结:
code_verifier:客户端先生成,最后放在 Request Body 中 POST 给服务器。code_challenge:客户端先计算,第一步就放在 URL 参数中发送给服务器。code:服务器在授权成功后生成,放在 Response 中返回给客户端。这三个参数形成了一个先承诺、后证明的过程。