You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.15 12:44:31