Skip to main content

4. Protocol (协议)

4.1 Client Creates a Code Verifier (客户端创建代码验证器)

客户端首先为每个 OAuth 2.0 [RFC6749] 授权请求以以下方式创建代码验证器 "code_verifier":

code_verifier = 使用 [RFC3986] 第 2.3 节中的未保留字符 
[A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~"
的高熵加密随机 STRING,
最小长度为 43 个字符, 最大长度为 128 个字符.

"code_verifier" 的 ABNF 如下:

code-verifier = 43*128unreserved
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
ALPHA = %x41-5A / %x61-7A
DIGIT = %x30-39

注意: 代码验证器应该 (SHOULD) 具有足够的熵, 使得猜测该值变得不切实际. 推荐 (RECOMMENDED) 使用合适的随机数生成器的输出来创建 32 个八位字节的序列. 然后将该八位字节序列进行 base64url 编码, 以生成一个 43 个八位字节的 URL 安全字符串用作代码验证器.

4.2 Client Creates the Code Challenge (客户端创建代码挑战)

然后, 客户端通过对代码验证器使用以下转换之一, 从代码验证器派生代码挑战:

plain

code_challenge = code_verifier

S256

code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))

如果客户端能够使用 "S256", 则必须 (MUST) 使用 "S256", 因为 "S256" 在服务器上是强制实现 (Mandatory To Implement, MTI) 的. 只有在客户端由于某些技术原因无法支持 "S256", 并且通过带外配置知道服务器支持 "plain" 时, 才允许使用 "plain".

plain 转换用于与现有部署的兼容性以及无法使用 S256 转换的受限环境.

"code_challenge" 的 ABNF 如下:

code-challenge = 43*128unreserved
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
ALPHA = %x41-5A / %x61-7A
DIGIT = %x30-39

4.3 Client Sends the Code Challenge with the Authorization Request (客户端在授权请求中发送代码挑战)

客户端使用以下附加参数将代码挑战作为 OAuth 2.0 授权请求 ([RFC6749] 第 4.1.1 节) 的一部分发送:

code_challenge : 必需 (REQUIRED). 代码挑战.

code_challenge_method : 可选 (OPTIONAL), 如果请求中不存在, 则默认为 "plain". 代码验证器转换方法为 "S256" 或 "plain".

4.4 Server Returns the Code (服务器返回代码)

当服务器在授权响应中颁发授权码时, 它必须 (MUST) 将 "code_challenge" 和 "code_challenge_method" 值与授权码关联起来, 以便稍后可以进行验证.

通常, "code_challenge" 和 "code_challenge_method" 值以加密形式存储在 "code" 本身中, 但也可以选择存储在服务器上与代码关联. 服务器禁止 (MUST NOT) 在客户端请求中以其他实体可以提取的形式包含 "code_challenge" 值.

服务器用于将 "code_challenge" 与颁发的 "code" 关联的确切方法超出了本规范的范围.

4.4.1 Error Response (错误响应)

如果服务器要求 OAuth 公共客户端使用代码交换证明密钥 (PKCE), 而客户端在请求中没有发送 "code_challenge", 则授权端点必须 (MUST) 返回授权错误响应, 其中 "error" 值设置为 "invalid_request". "error_description" 或 "error_uri" 的响应应该 (SHOULD) 解释错误的性质, 例如, 需要代码挑战.

如果支持 PKCE 的服务器不支持请求的转换, 则授权端点必须 (MUST) 返回授权错误响应, 其中 "error" 值设置为 "invalid_request". "error_description" 或 "error_uri" 的响应应该 (SHOULD) 解释错误的性质, 例如, 不支持转换算法.

4.5 Client Sends the Authorization Code and the Code Verifier to the Token Endpoint (客户端将授权码和代码验证器发送到令牌端点)

收到授权码后, 客户端将访问令牌请求发送到令牌端点. 除了 OAuth 2.0 访问令牌请求 ([RFC6749] 第 4.1.3 节) 中定义的参数外, 它还发送以下参数:

code_verifier : 必需 (REQUIRED). 代码验证器.

"code_challenge_method" 在颁发授权码时绑定到授权码. 这是令牌端点必须 (MUST) 用于验证 "code_verifier" 的方法.

4.6 Server Verifies code_verifier before Returning the Tokens (服务器在返回令牌之前验证 code_verifier)

在令牌端点收到请求后, 服务器通过从接收到的 "code_verifier" 计算代码挑战并将其与先前关联的 "code_challenge" 进行比较来验证它, 首先根据客户端指定的 "code_challenge_method" 方法进行转换.

如果第 4.3 节中的 "code_challenge_method" 是 "S256", 则将接收到的 "code_verifier" 通过 SHA-256 哈希, 进行 base64url 编码, 然后与 "code_challenge" 进行比较, 即:

BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) == code_challenge

如果第 4.3 节中的 "code_challenge_method" 是 "plain", 则直接比较它们, 即:

code_verifier == code_challenge

如果值相等, 令牌端点必须 (MUST) 继续正常处理 (如 OAuth 2.0 [RFC6749] 所定义). 如果值不相等, 则必须 (MUST) 返回错误响应, 指示 "invalid_grant", 如 [RFC6749] 第 5.2 节所述.