Skip to content

OAuth sign in isn't redirecting on the server side

这个限制的原因是 auth helpers 库缺少一个直接执行服务器端重定向的机制,因为每个框架处理重定向的方式都不一样。不过,该库确实通过它返回的数据属性提供了一个 URL,可以用来进行重定向。

🌐 The reason behind this limitation is that the auth helpers library lacks a direct mechanism for performing server-side redirects, as each framework handles redirects differently. However, the library does offer a URL through the data property it returns, which should be used for the purpose of redirection.

在 @supabase/ssr 的 PKCE 流程中,signInWithOAuth 会把 code verifier 存到 cookie 里。当你的 setAll 像在 Remix 一样把 Set-Cookie headers 收集到一个 Headers 对象里时,把它们传到重定向里。否则浏览器根本不会存 code verifier,回调交换就会失败。在 Next.js 和 SvelteKit 里,框架的 cookie API 会帮你写到响应里,所以重定向不需要额外操作。

🌐 With the PKCE flow in @supabase/ssr, signInWithOAuth stores the code verifier in a cookie. When your setAll collects Set-Cookie headers into a Headers object, as in Remix, pass them on the redirect. Otherwise the browser never stores the code verifier and the callback exchange fails. In Next.js and SvelteKit, the framework's cookie API writes to the response for you, so the redirect needs nothing extra.

Next.js:

import { NextResponse } from "next/server";
...
const { data } = await supabase.auth.signInWithOAuth({
provider: 'github',
})
return NextResponse.redirect(data.url)

SvelteKit:

import { redirect } from '@sveltejs/kit';
...
const { data } = await supabase.auth.signInWithOAuth({
provider: 'github',
})
throw redirect(303, data.url)

混音:

import { redirect, type ActionFunctionArgs } from '@remix-run/node'
import { createServerClient, parseCookieHeader, serializeCookieHeader } from '@supabase/ssr'
export async function action({ request }: ActionFunctionArgs) {
const responseHeaders = new Headers()
// Collect every cookie the client sets, so they can be sent with the redirect
const supabase = createServerClient(
process.env.SUPABASE_URL!,
process.env.SUPABASE_PUBLISHABLE_KEY!,
{
cookies: {
getAll() {
return parseCookieHeader(request.headers.get('Cookie') ?? '')
},
setAll(cookiesToSet, cacheHeaders) {
cookiesToSet.forEach(({ name, value, options }) =>
responseHeaders.append('Set-Cookie', serializeCookieHeader(name, value, options))
)
Object.entries(cacheHeaders).forEach(([key, value]) => responseHeaders.set(key, value))
},
},
}
)
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'github',
})
if (error) throw error
return redirect(data.url, { headers: responseHeaders })
}