React Router v7集成Supabase OAuth时出现无效请求错误:auth code与code verifier均不能为空
React Router v7集成Supabase OAuth时出现无效请求错误:auth code与code verifier均不能为空
嘿,我碰到过好几个类似的问题,这个错误基本都是PKCE OAuth流程里的code verifier没处理好导致的——要么是跳转前没把它存在cookie里,要么是回调的时候没正确读出来。我来帮你看看你的代码哪里需要调整:
第一步:修复signupWithOAuth函数,别漏了存code verifier
你原来的signup函数只处理了OAuth的跳转请求,但没把Supabase返回的关键cookie(包含code verifier)返回给客户端,这就导致后面回调的时候完全找不到验证用的code verifier了。改完之后的代码应该是这样:
export const signupWithOAuth = async ({ request, provider, }: { provider: 'google' | 'github' request: Request }) => { const supabaseClient = createSupabaseServerClient({ request }) // 这里要接收返回的headers,里面包含code verifier的cookie const { data, error, headers } = await supabaseClient.auth.signInWithOAuth({ provider: provider, options: { redirectTo: `${new URL(request.url).origin}/auth/callback`, }, }) if (error) { console.error(error) throw new Error(`Failed to sign up with OAuth, ${error.message}`) } // 解析headers里的Set-Cookie,拿到code verifier的cookie const authCookies = parseCookieHeader(headers.get('set-cookie') || '') // 要把这些cookie返回给客户端,比如在Remix里可以通过headers设置 return { data, authCookies } }
这里的核心是要把Supabase返回的headers里的cookie提取出来,返回给客户端存在浏览器里,不然回调的时候就拿不到code verifier了。
第二步:完善auth.callback.ts的loader逻辑
你原来的loader代码只提到了取code,但没处理cookie读取和session交换的核心逻辑,完整的loader应该这么写:
import { redirect, type LoaderFunctionArgs } from '@remix-run/node' import { createServerClient, parseCookieHeader, serializeCookieHeader } from '@supabase/ssr' export async function loader({ request }: LoaderFunctionArgs) { const requestUrl = new URL(request.url) const code = requestUrl.searchParams.get('code') // 先检查code是否存在,没有的话直接抛出错误 if (!code) { throw new Error('OAuth授权code未在请求中找到') } // 解析客户端传来的cookie,里面包含之前存的code verifier const clientCookies = parseCookieHeader(request.headers.get('Cookie') || '') // 创建Supabase服务端客户端,要正确绑定cookie的读写方法 const supabaseClient = createServerClient( process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, { cookies: { get: (key) => clientCookies[key], set: (key, value, options) => { // 把Supabase更新的auth cookie存到临时对象里 clientCookies[key] = value }, }, } ) // 用拿到的code和cookie里的code verifier交换用户session const { data, error } = await supabaseClient.auth.exchangeCodeForSession(code) if (error) { console.error('OAuth回调处理失败:', error) throw new Error(`会话交换失败: ${error.message}`) } // 序列化更新后的auth cookie,设置到响应头里返回给客户端 const updatedCookies = serializeCookieHeader(clientCookies) // 跳转到你的应用首页,替换成你实际的路由 const response = redirect('/') response.headers.set('Set-Cookie', updatedCookies) return response }
几个容易踩坑的点要注意
- 一定要确保
SUPABASE_URL和SUPABASE_ANON_KEY这两个环境变量配置正确,少一个或者拼写错了都会出问题 - Supabase控制台里的Site URL和Redirect URLs必须和你代码里的
redirectTo完全一致,包括http/https和端口号,差一个字符都不行 - 不管是signup还是callback,都要保证Supabase客户端的cookie读写逻辑正确,这是服务端渲染场景下OAuth的核心
这样调整之后,code verifier会被正确存在客户端,callback的时候也能正确读取并和code一起完成验证,那个错误应该就会消失了。
备注:内容来源于stack exchange,提问作者Santi
相关产品推荐
相关产品推荐

