PKCE 流程
About authenticating with PKCE flow.
代码交换的验证密钥(PKCE)流程是用户可以认证的一种方式,同时你的应用也能获取必要的访问和刷新令牌。
🌐 The Proof Key for Code Exchange (PKCE) flow is one of two ways that a user can authenticate and your app can receive the necessary access and refresh tokens.
这个流程是由 Supabase Auth 为你处理的实现细节,但理解 PKCE 和 隐式流程 之间的区别,对于理解仅客户端认证和服务器端认证的区别很重要。
🌐 The flow is an implementation detail handled for you by Supabase Auth, but understanding the difference between PKCE and implicit flow is important for understanding the difference between client-only and server-side auth.
它是怎么运作的 #
🌐 How it works
验证成功后,用户会被重定向到你的应用,网址看起来像这样:
🌐 After a successful verification, the user is redirected to your app with a URL that looks like this:
https://yourapp.com/...?code=<...>code 参数通常被称为认证码,可以通过调用 exchangeCodeForSession(code) 来交换访问令牌。
🌐 The code parameter is commonly known as the Auth Code and can be exchanged for an access token by calling exchangeCodeForSession(code).
为了安全起见,这个代码有效期为5分钟,并且只能兑换一次访问令牌。如果你想获得新的访问令牌,需要从头重新开始认证流程。
🌐 For security purposes, the code has a validity of 5 minutes and can only be exchanged for an access token once. You will need to restart the authentication flow from scratch if you wish to obtain a new access token.
由于流程是在服务器端运行的,localStorage 可能不可用。你可以通过将 storage 选项设置为包含以下方法的对象,来配置客户端库使用自定义存储适配器和备用存储(例如 cookies):
🌐 As the flow is run server side, localStorage may not be available. You may configure the client library to use a custom storage adapter and an alternate backing storage such as cookies by setting the storage option to an object with the following methods:
const : = { : () => { if (!()) { // Configure alternate storage return null } return ..() }, : (, ) => { if (!()) { // Configure alternate storage here return } ..(, ) }, : () => { if (!()) { // Configure alternate storage here return } ..() },}你也可以配置客户端库在成功重定向后自动将其交换为会话。这可以通过将 detectSessionInUrl 选项设置为 true 来完成。
🌐 You may also configure the client library to automatically exchange it for a session after a successful redirect. This can be done by setting the detectSessionInUrl option to true.
综合起来,你的客户端库初始化可能看起来像这样:
🌐 Putting it all together, your client library initialization may look like this:
const = ('https://your-project-id.supabase.co', 'sb_publishable_...', { // ... : { // ... : true, : 'pkce', : { : () => .('FETCHED_TOKEN'), : () => {}, : () => {}, }, }, // ...})限制 #
🌐 Limitations
在幕后,代码交换需要一个代码验证器。URL里的代码和代码验证器都会被发送回认证服务器以完成交换。
🌐 Behind the scenes, the code exchange requires a code verifier. Both the code in the URL and the code verifier are sent back to the Auth server for a successful exchange.
当身份验证流程首次启动时,代码验证器会被创建并保存在本地。这意味着代码交换必须在启动流程的同一浏览器和设备上进行。
🌐 The code verifier is created and stored locally when the Auth flow is first initiated. That means the code exchange must be initiated on the same browser and device where the flow was started.
重叠的流 #
🌐 Overlapping flows
如果在同一个浏览器上启动多个 PKCE 流程而其中任意一个还没完成(例如,在两个标签页中调用了 signInWithOAuth()),之前流程存储的 code verifier 会被后来的覆盖,导致第一个流程的 code 交换失败。
🌐 If more than one PKCE flow is started on the same browser before either one completes (for example, signInWithOAuth() called in two tabs), the code verifier stored for the earlier flow is overwritten by the later one, and exchanging the first flow's code fails.
实验性的
对重叠流的支持目前处于实验阶段,需要明确选择加入,因为 API 可能会在没有通知的情况下更改。
🌐 Support for overlapping flows is currently experimental and requires explicit opt-in as the API may change without notice.
为了让每个流程的验证器保持独立,在创建客户端时设置 appendPkceFlowIdToRedirects 选项:
🌐 To keep each flow's verifier separate, set the appendPkceFlowIdToRedirects option when creating the client:
const supabase = createClient(supabaseUrl, supabaseKey, { auth: { experimental: { appendPkceFlowIdToRedirects: true }, },})启用此功能后,客户端库会向 redirectTo 添加一个 sb_flow_id 查询参数,这样你的 OAuth 回调页面就可以读取它,并用来选择匹配的验证器。你也可以直接从 signInWithOAuth() 的响应中获取流程 ID:
🌐 With this enabled, the client library appends a sb_flow_id query parameter to redirectTo, so your OAuth callback page can read it back and use it to select the matching verifier. You can also get the flow ID directly from the response of signInWithOAuth():
const { data, error } = await supabase.auth.signInWithOAuth({ provider: 'github',})const flowId = data.flowId将流 ID 传给 exchangeCodeForSession(),以确保使用正确的验证器,无论你是从 data.flowId 读取,还是从重定向 URL 中的 sb_flow_id 查询参数读取:
🌐 Pass the flow ID to exchangeCodeForSession() to make sure the correct verifier is used, whether you read it from data.flowId or from the sb_flow_id query parameter in the redirect URL:
const { data, error } = await supabase.auth.exchangeCodeForSession(authCode, { flowId })资源 #
🌐 Resources
- OAuth 2.0 指南 到 PKCE 流程