Supabase OAuth登录问题:受保护路由登录后无法返回原地址
解决Supabase OAuth登录的Code Challenge不匹配与重定向问题
问题1:Code Challenge不匹配错误修复
原因
中间件调用signInWithOAuth时,Supabase会生成并存储code verifier到cookie,但原代码的cookie处理逻辑没有正确将这些cookie写入响应,导致重定向到Google登录时丢失verifier,回调阶段exchangeCodeForSession无法匹配验证。
修改后的Supabase中间件代码
import { createServerClient } from "@supabase/ssr"; import { NextResponse, type NextRequest } from "next/server"; export async function updateSession(request: NextRequest) { let supabaseResponse = NextResponse.next({ request }); const supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { cookies: { getAll() { return request.cookies.getAll(); }, setAll(cookiesToSet) { // 同步更新request和响应的cookie,确保verifier不丢失 cookiesToSet.forEach(({ name, value, options }) => { request.cookies.set(name, value, options); supabaseResponse.cookies.set(name, value, options); }); }, }, } ); const { data: { user } } = await supabase.auth.getUser(); if (!user) { const redirectTo = request.nextUrl.pathname; const { data, error: signInError } = await supabase.auth.signInWithOAuth({ provider: "google", options: { // 对路径编码,避免特殊字符解析错误 redirectTo: `${request.nextUrl.origin}/auth/callback?redirectTo=${encodeURIComponent(redirectTo)}`, }, }); if (signInError) { console.error("登录错误:", signInError.message); throw new Error("OAuth登录失败"); } if (data?.url) { return NextResponse.redirect(data.url); } } return supabaseResponse; }
问题2:登录后重定向到原页面修复
原因
原回调路由错误拼接next和redirectTo参数,导致路径格式错误;同时未正确区分两种登录场景的目标路径。
修改后的回调路由代码
import { NextResponse } from "next/server"; import { createClient } from "@/utils/supabase/server"; export async function GET(request: Request) { const { searchParams, origin } = new URL(request.url); const code = searchParams.get("code"); // 解码获取目标路径,默认对应添加产品按钮的跳转地址 const redirectTo = decodeURIComponent(searchParams.get("redirectTo") ?? "/dashboard/create"); if (code) { const supabase = createClient(); const { error } = await supabase.auth.exchangeCodeForSession(code); if (!error) { const forwardedHost = request.headers.get("x-forwarded-host"); const targetUrl = new URL(redirectTo, origin); // 根据环境构建正确的重定向地址 if (process.env.NODE_ENV !== "development" && forwardedHost) { targetUrl.host = forwardedHost; targetUrl.protocol = "https:"; } return NextResponse.redirect(targetUrl.toString()); } } // 登录失败跳转错误页 return NextResponse.redirect(`${origin}/auth/auth-code-error`); }
修改后的Server Action代码
"use server"; import { createClient } from "@/utils/supabase/server"; import { redirect } from "next/navigation"; export default async function signIn() { const supabase = createClient(); const { data, error } = await supabase.auth.signInWithOAuth({ provider: "google", options: { // 指定添加产品按钮登录后的默认跳转路径 redirectTo: `${process.env.NEXT_PUBLIC_SUPABASE_URL}/auth/callback?redirectTo=/dashboard/create`, }, }); if (error) { console.error("登录错误:", error.message); throw new Error("OAuth登录失败"); } if (data.url) { redirect(data.url); } }
验证步骤
- 访问受保护路由(如
/dashboard),自动跳转Google登录,完成后返回原路由 - 点击“添加产品”按钮,登录后跳转至
/dashboard/create - 控制台无
code challenge does not match错误输出
内容的提问来源于stack exchange,提问作者illuminate
相关产品推荐
相关产品推荐

