VoociiBlog
HomeBlogAI TrendingPortfolioBooksLinksToolsAbout
© 2026 Voocii. Built with Next.js & tRPC.
GitHubXEmailRSS


OAuth 2.0 + PKCE中的三个code:code_verifier, code_challenge, code

AuthRickRickFebruary 25, 2025·6 views

在 OAuth 2.0 + PKCE(Proof Key for Code Exchange)认证过程中,这三个参数分别承担不同的职责:

  • code_verifier:客户端生成的原始随机密钥,只有客户端自己保存。
  • code_challenge:客户端根据 code_verifier 计算出来的摘要,发送给认证服务器。
  • code:认证服务器在用户授权成功后生成的临时授权码,再由客户端拿它去交换 Token。

最重要的一点是:PKCE 的核心就是让客户端在申请 Token 时,证明自己持有最初生成的 code_verifier。

一、三个参数分别由谁生成?

参数生成方生成时机作用
code_verifier客户端发起认证之前原始随机密钥
code_challenge客户端发起认证之前verifier 的 SHA-256 摘要
code认证服务器用户授权成功之后临时授权凭证

1. code_verifier

由客户端生成。

例如,客户端生成一个足够长、随机且不可预测的字符串:

code_verifier = dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

这个值有几个特点:

  • 随机生成。
  • 每次认证都应该重新生成。
  • 只保存在客户端,不直接发送给授权服务器的授权端点。
  • 在后续申请 Token 时通过 POST 方法放在 Request Body 里以加密方式发送给服务器。

2. code_challenge

同样由客户端生成。

客户端使用刚才的 code_verifier,通过 SHA-256 计算摘要,然后进行 Base64URL 编码:

code_challenge = BASE64URL(SHA256(code_verifier))

注意,这里通常使用 S256 模式,而不是 plain 模式。

客户端在发起授权请求时,将 code_challenge 和 code_challenge_method 直接放在 URL 里以明文方式发送给认证服务器。认证服务器必须保存 code_challenge 和 code_challenge_method

3. code

由认证服务器生成,并临时保存在内存(或者外部存储)中。这个 code 必须关联对应的 client_id 和 redirect_uri。

当用户完成登录并同意授权后,认证服务器生成一个临时授权码:

authorization_code = "SplxlOBeZQQYbYS6WxSbIA"

然后通过客户端预先指定的 Redirect URI,将这个 code (附在 Response 中以明文方式)返回给客户端。

客户端拿到 code 后,才能进入下一步 Token 交换流程。

二、完整的客户端与服务器通信流程

我们把整个过程分成两个阶段:

阶段一:申请授权码(Authorization Request)

  1. 客户端生成 code_verifier

    客户端本地生成随机字符串,并保存起来。

  2. 客户端计算 code_challenge

    使用 SHA-256 + Base64URL 计算摘要。

  3. 客户端向授权服务器发送授权请求

    通过浏览器跳转到 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。

  4. 服务器记录 code_challenge

    服务器将 code_challenge 和计算方法 code_challenge_method 与本次授权请求关联起来。

  5. 用户完成登录和授权

    授权服务器生成 code。

  6. 服务器重定向回客户端

    HTTP/1.1 302 Found
    
    Location: https://client.com/callback?code=XYZ123
    

    客户端从回调 URL 中获取 code。

阶段二:交换 Token(Token Request)

  1. 客户端向 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...
    
  2. 服务器验证 PKCE

    服务器拿到 code_verifier,重新计算:

    BASE64URL(SHA256(code_verifier))
    

    然后与之前保存的 code_challenge 比较。

  3. 验证通过,返回 Token

    {
      "access_token": "...",
      "refresh_token": "...",
      "token_type": "Bearer"
    }
    

    验证失败则拒绝本次 Token 交换。

依据:RFC 7636 第 4.1~4.6 节。

三、用一张图理解三个参数的传递关系

oauth-pkce-code-flow.jpeg

四、为什么需要 PKCE?

假设没有 PKCE:

  1. 客户端向服务器申请授权码。
  2. 用户登录成功,服务器返回 code。
  3. 攻击者如果截获了这个 code,就可能尝试拿它去兑换 Access Token。

加入 PKCE 后:

  1. 攻击者即使截获了 code。
  2. 也不知道客户端最初生成的 code_verifier。
  3. 因此无法通过服务器的 PKCE 验证,不能成功兑换 Token。

这就是 PKCE 的核心安全机制:授权码本身不再足以兑换 Token,还必须提供最初生成的随机凭证。

五、结合你熟悉的 OAuth 服务端开发,特别注意一点

如果你自己实现 OAuth 2.0 Authorization Server,需要注意:

  • Authorization Endpoint:接收 code_challenge 和 code_challenge_method。
  • 生成 Authorization Code 时:把 challenge 和 method 与 code 绑定。
  • Token Endpoint:接收 code 和 code_verifier。
  • 验证时:根据 code 找到之前关联的 challenge,再计算并比较。

这里有个非常重要的细节:

服务器不需要保存 code_verifier,只需要保存 code_challenge 和 code_challenge_method。

因为服务器可以在 Token 请求阶段,根据客户端传来的 verifier 重新计算 challenge。

另外,授权码应该是短期有效、一次性使用的,并且要绑定对应的客户端和 redirect_uri。

最后总结:

  • code_verifier:客户端先生成,最后放在 Request Body 中 POST 给服务器。
  • code_challenge:客户端先计算,第一步就放在 URL 参数中发送给服务器。
  • code:服务器在授权成功后生成,放在 Response 中返回给客户端。

这三个参数形成了一个先承诺、后证明的过程。

官方规范:RFC 7636 – Proof Key for Code Exchange

Comments (0)

No comments yet. Be the first!

Leave a comment

On this page
  • 一、三个参数分别由谁生成?
  • 二、完整的客户端与服务器通信流程
  • 三、用一张图理解三个参数的传递关系
  • 四、为什么需要 PKCE?
  • 五、结合你熟悉的 OAuth 服务端开发,特别注意一点