Next.js 15中Supabase Google OAuth PKCE报错:auth code与code verifier不能为空
Next.js 15 + Supabase Google OAuth PKCE 认证错误:
"invalid request: both auth code and code verifier should be non-empty" 我在Next.js 15应用中集成Supabase Google OAuth PKCE认证时遇到持续问题,多次尝试修复后,OAuth重定向后仍收到错误:"invalid request: both auth code and code verifier should be non-empty"。
客户端OAuth初始化代码
const handleGoogleSignIn = async () => { const redirectTo = `${window.location.origin}/auth/callback/student`; const { data, error } = await supabase.auth.signInWithOAuth({ provider: 'google', options: { redirectTo, queryParams: { prompt: 'consent', access_type: 'offline' } }, }); if (data?.url) { window.location.href = data.url; } };
Supabase客户端配置
export const supabase = createBrowserClient(supabaseUrl, supabaseAnonKey, { auth: { flowType: 'pkce', storage: typeof window !== 'undefined' ? window.localStorage : undefined, storageKey: 'sb-auth-token', }, })
OAuth回调处理器
export async function GET(request: NextRequest, { params }: RouteParams) { const code = requestUrl.searchParams.get('code'); if (code && !type) { // DEBUG: Log all cookies console.log('All cookies:', cookieStore.getAll().map(c => c.name)); // Manually extract code verifier cookie const codeVerifierCookie = cookieStore.get('sb-auth-token-code-verifier'); console.log('Code verifier cookie exists:', !!codeVerifierCookie); if (!codeVerifierCookie?.value) { // Redirect with error return NextResponse.redirect(new URL(`${loginRoute}?error=Code verifier not found`, requestUrl.origin)); } // Decode the code verifier (Supabase double-encodes it) let decodedVerifier: string; const rawValue = codeVerifierCookie.value; if (rawValue.startsWith('base64-')) { decodedVerifier = JSON.parse(atob(rawValue.replace('base64-', ''))); } else { decodedVerifier = rawValue; } // Manual token exchange const tokenResponse = await fetch(`${supabaseUrl}/auth/v1/token?grant_type=pkce`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'apikey': supabaseAnonKey, 'Authorization': `Bearer ${supabaseAnonKey}`, }, body: JSON.stringify({ auth_code: code, code_verifier: decodedVerifier, }), }); if (!tokenResponse.ok) { const errorText = await tokenResponse.text(); console.error('Token exchange failed:', tokenResponse.status, errorText); // Handle error... } const tokenData = await tokenResponse.json(); // Set session and redirect... } }
中间件配置片段
const isPublicPage = req.nextUrl.pathname === ROUTES.HOME || req.nextUrl
错误流程详情
- 用户点击“Continue with Google”
- 跳转到Google OAuth授权页面
- 授权完成后,重定向至
/auth/callback/student?code=...&scope=... - 服务器日志显示:
"Token exchange failed: 400 {"error":"invalid_request","error_description":"both auth code and code verifier should be non-empty"}"
排查与修复方案
1. 避免手动处理PKCE流程(核心修复)
Supabase SDK已内置完整PKCE流程处理,手动提取code verifier并调用token接口极易出错。直接使用官方auth.exchangeCodeForSession方法替代手动请求:
export async function GET(request: NextRequest) { const url = new URL(request.url); const code = url.searchParams.get('code'); if (code) { const supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { cookies: { getAll: () => request.cookies.getAll(), set: (name, value, options) => request.cookies.set(name, value, options), remove: (name, options) => request.cookies.delete(name, options), }, } ); const { data, error } = await supabase.auth.exchangeCodeForSession(code); if (error) { console.error('Session exchange failed:', error); return NextResponse.redirect(new URL('/login?error=auth_failed', url.origin)); } return NextResponse.redirect(new URL('/dashboard', url.origin)); } return NextResponse.redirect(new URL('/login', url.origin)); }
2. 修正中间件白名单配置
补全isPublicPage判断,将回调路由加入白名单,避免中间件拦截认证Cookie:
const isPublicPage = req.nextUrl.pathname === ROUTES.HOME || req.nextUrl.pathname.startsWith('/auth/callback');
3. 验证Cookie访问权限
确保sb-auth-token-code-verifier Cookie的路径配置正确,回调路由/auth/callback/student必须能读取到该Cookie。若使用子域名,需检查Cookie的domain参数是否匹配。
4. 统一客户端与服务端配置
- 客户端和服务端的Supabase配置需保持一致,服务端创建
createServerClient时无需额外指定flowType,SDK会自动适配PKCE流程。 - 确认Supabase控制台中设置的授权回调URL与代码中
redirectTo参数完全一致(包含协议、域名、完整路径)。
5. 修正手动解码逻辑(若坚持自定义流程)
Supabase存储的code verifier是原始字符串,无需base64解码,错误解码会导致verifier无效:
// 移除多余解码步骤,直接使用Cookie值 const decodedVerifier = codeVerifierCookie.value;
内容的提问来源于stack exchange,提问作者Saaif Suleman
相关产品推荐
相关产品推荐

