Supabase Auth回调异常:成功认证后仍要求code_verifier与auth_code
NextJS 13(App Router)+ FastAPI + Supabase 认证异常:登录流程完成后仍提示缺少auth code和code verifier
环境配置
使用Supabase处理认证,前端通过AuthCallback组件处理OAuth回调:
// AuthCallback.tsx 'use client'; import { useEffect } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { useToast } from "@/hooks/use-toast"; import axios, { AxiosError } from 'axios'; import { BACKEND_URL } from '../src/lib/utils'; export default function AuthCallback() { const router = useRouter(); const searchParams = useSearchParams(); const { toast } = useToast(); useEffect(() => { const handleCallback = async () => { const code = searchParams.get('code'); const provider = searchParams.get('provider'); if (code) { try { const response = await axios.post(`${BACKEND_URL}/api/auth/callback/${provider}`, { code }); if (response.data.user) { localStorage.setItem('access_token', response.data.session.access_token); router.push('/dashboard'); } else { throw new Error('Login failed'); } } catch (error) { // Hack if (error instanceof AxiosError && error.response?.data.detail === "invalid request: both auth code and code verifier should be non-empty" && localStorage.getItem('access_token') && provider === 'google' ) { router.push('/dashboard'); } else { router.push('/'); } } } else { router.push('/'); } }; handleCallback(); }, [searchParams, router, toast]); return <div>Processing authentication...</div>; }
后端通过FastAPI路由处理回调请求:
# auth.py from fastapi import APIRouter, HTTPException, Depends from supabase import create_client, Client import os from api.utils.auth_middleware import get_current_user from pydantic import BaseModel router = APIRouter() url = os.environ.get("SUPABASE_URL") key = os.environ.get("SUPABASE_SERVICE_KEY") supabase: Client = create_client(url, key) class CallbackInput(BaseModel): code: str @router.post("/api/auth/callback/{provider}") async def auth_callback(provider: str, input: CallbackInput): try: response = supabase.auth.exchange_code_for_session({"auth_code": input.code}) if response.user: return {"user": response.user, "session": response.session} else: raise HTTPException(status_code=400, detail="Failed to exchange code for session") except Exception as e: print(f"Error in auth_callback: {str(e)}") raise HTTPException(status_code=400, detail=str(e))
问题现象
经调试确认以下事实:
- 已成功从URL参数中获取到
code; - 后端成功调用
exchange_code_for_session并返回有效响应; - 在Supabase的
gotrue_client.py中,exchange_code_for_session执行时code_verifier存在于存储中:
# gotrue_client.py (excerpt) def exchange_code_for_session(self, params: CodeExchangeParams): code_verifier = params.get("code_verifier") or self._storage.get_item( f"{self._storage_key}-code-verifier" ) response = self._request( "POST", "token?grant_type=pkce", body={ "auth_code": params.get("auth_code"), "code_verifier": code_verifier, }, redirect_to=params.get("redirect_to"), xform=parse_auth_response, ) self._storage.remove_item(f"{self._storage_key}-code-verifier") if response.session: self._save_session(response.session) self._notify_all_subscribers("SIGNED_IN", response.session) return response
access_token已成功存入localStorage。
但调用router.push('/dashboard')后,立即抛出错误:
AxiosError: invalid request: both auth code and code verifier should be non-empty
临时解决方案
实现了一个临时绕过方案,但存在安全隐患,且控制台会输出POST http://localhost:8000/api/auth/callback/google 400 (Bad Request)错误:
catch (error) { if (error instanceof AxiosError && error.response?.data.detail === "invalid request: both auth code and code verifier should be non-empty" && localStorage.getItem('access_token') && provider === 'google' ) { router.push('/dashboard'); } else { router.push('/'); } }
已尝试的排查步骤
- 确认
exchange_code_for_session调用时code_verifier存在,且回调完成后已被移除; - 确认交换流程中
auth_code和code_verifier均非空; - 逐行调试代码(包括
exchange_code_for_session的实现),未找到错误来源。
疑问
明明auth_code和code_verifier存在且已被成功使用,为何仍会出现该错误?看起来错误发生在流程再次循环时,此时code_verifier已被销毁。希望了解问题的根本原因,而非仅依赖临时方案。
内容的提问来源于stack exchange,提问作者theGreenCabbage
相关产品推荐
相关产品推荐

