PKCE(读作pixy)是RFC: 7636 Proof Key for Code Exchange by OAuth Public Clients对OAuth2.0的Authorization Code Flow所做的扩展。
Authorization Code Flow需要客户端持有client_id和client_secret。client_id在第一步用来换取authz code,client_secret在第二步用来换取access token。如果是桌面或者移动app这些非云端应用的话,client_id和client_secret都要打包到app中。因为app的内容是运行在客户端的电脑上的,所以打包的client_id和client_secret容易泄露。rfc7636把这些app成为public client,假定这些app不能保守client_id和client_secret,并为破除这个弊端,打造了Proof Key for Code Exchange这个流程来至少避免把client_secret打包到app中。
rfc7636的思想很简单,就是让public client在运行时候使用一次性生成的随机码来向服务器换取code,服务器需要记住用于交互用的随机码,在签发access token的时候需要检查客户端提交的随机码(或者生成随机码的生成码),如果不对则拒绝签发access token。
具体操作过程如下:
- 客户端生成一个code_verifier,作为生成码
- 生成码必须是强随机的,不能被猜到。长度从43到128之间,可以包括在Section 2.3 of [RFC3986]中定义的字符
- 客户端可以直接把生成码发给服务端,或者把调理后的生成码发给服务端
- 生成码在request_uri的code_challenge 参数中传递
- 如果不调理,那么需要在request_uri指定code_challenge_method参数为plain
- 如果调理,目前只有sha256一种调理方法。如果使用的话,需要在request_uri指定code_challenge_method参数为S256,并通过
BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
来生成code_challenge
- 服务端返回authz code
- 客户端发送authz code和code_verifier到服务端令牌端点
- 服务端验证authz code和code_verifier,然后返回access token
参考
- 为客户端而生的OAuth2.0协议之PKCE授权码模式
- The Client ID and Secret
- Why OAuth API Keys and Secrets Aren’t Safe in Mobile Apps
- App attestation techniques close common authentication gaps
- What’s the right OAuth 2.0 flow for a mobile app
- Implement the OAuth 2.0 Authorization Code with PKCE Flow
- Microsoft identity platform and OAuth 2.0 authorization code flow
2020-05-1更新
使用Python来模拟生成code_verifier和code_challenge的算法:
>>> import string, base64
>>> from hashlib import sha256
>>> code_verifier = ''.join(random.choice(string.ascii_lowercase) for i in range(32))
>>> code_verifier
'auriavjuviqiojozncangfshwfzvsvyv'
>>> code_challenge = base64.urlsafe_b64encode(sha256(code_verifier.encode()).digest())..rstrip(b'=')
>>> code_challenge
'gb1c_gwBtQqi5EXpMGi5XaJVfkeXQJGrba0PS-93Qcg'
>>> len(code_challenge)
43
>>> base64.urlsafe_b64encode(sha256(b'auriavjuviqiojozncangfshwfzvsvyv').digest()).rstrip(b'=')
b'gb1c_gwBtQqi5EXpMGi5XaJVfkeXQJGrba0PS-93Qcg'
(更新完)