Skip to content

How to Migrate from Supabase Auth Helpers to SSR package

auth-helpers 包已被弃用,取而代之的是 @supabase/ssr 包。我们建议迁移到 @supabase/ssr 包,因为未来的错误修复和功能更新将主要集中在 @supabase/ssr 包上。

🌐 The auth-helpers packages are deprecated and replaced with the @supabase/ssr package. We recommend migrating to the @supabase/ssr package as future bug fixes and feature releases are focused on the @supabase/ssr package.

这里有一些步骤,帮助你把应用从 auth-helpers 包迁移到 @supabase/ssr 包。

🌐 Here are the steps for you to migrate your application from the auth-helpers package to @supabase/ssr package.

根据你的实现,你可以忽略这部分文档并使用你自己的实现(比如用 API 路由而不是服务器操作)。重要的是,你要用 @supabase/ssr 提供的客户端创建的工具函数替换掉 auth-helpers 提供的客户端。

🌐 Depending on your implementation, you may ignore some parts of this documentation and use your own implementation (i.e. using API routes vs. Server Actions). What's important is you replace the clients provided by auth-helpers with the utility functions created using clients provided by @supabase/ssr.

1. 卸载 Supabase Auth 辅助工具,然后安装 Supabase SSR 包 #

🌐 1. Uninstall Supabase Auth helpers and install the Supabase SSR package

重要的是,你不要在同一个应用里同时使用 auth-helpers-nextjs@supabase/ssr 包,以免遇到认证问题。

🌐 It's important that you don't use both auth-helpers-nextjs and @supabase/ssr packages in the same application to avoid running into authentication issues.

1
npm uninstall @supabase/auth-helpers-nextjs @supabase/supabase-js
2
npm install @supabase/ssr @supabase/supabase-js

2. 创建用于生成 Supabase 客户端的库函数 #

🌐 2. Create the library functions to create Supabase clients

1
// lib/supabase/client.ts
2
3
import { createBrowserClient } from '@supabase/ssr';
4
5
export function createClient() {
6
return createBrowserClient(
7
process.env.NEXT_PUBLIC_SUPABASE_URL!,
8
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
9
);
10
}
11
12
// lib/supabase/server.ts
13
import { createServerClient } from '@supabase/ssr'
14
import { cookies } from 'next/headers'
15
16
export async function createClient() {
17
const cookieStore = await cookies()
18
19
return createServerClient(
20
process.env.NEXT_PUBLIC_SUPABASE_URL!,
21
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
22
{
23
cookies: {
24
getAll() {
25
return cookieStore.getAll()
26
},
27
setAll(cookiesToSet, _headers) {
28
try {
29
cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options))
30
} catch {
31
// The `setAll` method was called from a Server Component.
32
// This can be ignored if you have middleware refreshing
33
// user sessions.
34
}
35
},
36
},
37
}
38
)
39
}
40
41
// lib/supabase/proxy.ts
42
import { createServerClient } from '@supabase/ssr'
43
import { NextResponse, type NextRequest } from 'next/server'
44
45
export async function updateSession(request: NextRequest) {
46
let supabaseResponse = NextResponse.next({
47
request,
48
})
49
50
// With Fluid compute, don't put this client in a global environment
51
// variable. Always create a new one on each request.
52
const supabase = createServerClient(
53
process.env.NEXT_PUBLIC_SUPABASE_URL!,
54
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
55
{
56
cookies: {
57
getAll() {
58
return request.cookies.getAll()
59
},
60
setAll(cookiesToSet, headers) {
61
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))
62
supabaseResponse = NextResponse.next({
63
request,
64
})
65
cookiesToSet.forEach(({ name, value, options }) => supabaseResponse.cookies.set(name, value, options))
66
Object.entries(headers).forEach(([key, value]) =>
67
supabaseResponse.headers.set(key, value)
68
)
69
},
70
},
71
}
72
)
73
74
// Do not run code between createServerClient and
75
// supabase.auth.getClaims(). A basic mistake could make it very hard to debug
76
// issues with users being randomly logged out.
77
78
// IMPORTANT: If you remove getClaims() and you use server-side rendering
79
// with the Supabase client, your users may be randomly logged out.
80
const { data } = await supabase.auth.getClaims()
81
82
const user = data?.claims
83
84
if (
85
!user &&
86
!request.nextUrl.pathname.startsWith('/login') &&
87
!request.nextUrl.pathname.startsWith('/auth')
88
) {
89
// no user, potentially respond by redirecting the user to the login page
90
const url = request.nextUrl.clone()
91
url.pathname = '/login'
92
return NextResponse.redirect(url)
93
}
94
95
// IMPORTANT: You *must* return the supabaseResponse object as it is. If you're
96
// creating a new response object with NextResponse.next() make sure to:
97
// 1. Pass the request in it, like so:
98
// const myNewResponse = NextResponse.next({ request })
99
// 2. Copy over the cookies, like so:
100
// myNewResponse.cookies.setAll(supabaseResponse.cookies.getAll())
101
// 3. Change the myNewResponse object to fit your needs, but avoid changing
102
// the cookies!
103
// 4. Finally:
104
// return myNewResponse
105
// If this is not done, you may be causing the browser and server to go out
106
// of sync and terminate the user's session prematurely!
107
108
return supabaseResponse
109
}

3. 替换你的 proxy.ts 文件 #

🌐 3. Replace your proxy.ts file

1
// proxy.ts
2
3
import { type NextRequest } from "next/server"
4
import { updateSession } from "@/lib/supabase/proxy"
5
6
export async function proxy(request: NextRequest) {
7
return await updateSession(request)
8
}
9
10
export const config = {
11
matcher: [
12
/*
13
* Match all request paths except for the ones starting with:
14
* - _next/static (static files)
15
* - _next/image (image optimization files)
16
* - favicon.ico (favicon file)
17
* Feel free to modify this pattern to include more paths.
18
*/
19
"/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
20
],
21
}

4. 创建你的服务器操作来处理登录和注册 #

🌐 4. Create your server actions to handle login and sign up

1
// app/login/actions.ts
2
3
'use server';
4
5
import { revalidatePath } from 'next/cache';
6
import { redirect } from 'next/navigation';
7
8
import { createClient } from '@/lib/supabase/server';
9
10
export async function login(formData: FormData) {
11
const supabase = createClient();
12
13
// type-casting here for convenience
14
// in practice, you should validate your inputs
15
const data = {
16
email: formData.get('email') as string,
17
password: formData.get('password') as string,
18
};
19
20
const { error } = await supabase.auth.signInWithPassword(data)
21
22
if (error) {
23
redirect('/error');
24
}
25
26
revalidatePath('/', 'layout');
27
redirect('/');
28
}
29
30
export async function signup(formData: FormData) {
31
const supabase = createClient();
32
33
// type-casting here for convenience
34
// in practice, you should validate your inputs
35
const data = {
36
email: formData.get('email') as string,
37
password: formData.get('password') as string,
38
};
39
40
const { error } = await supabase.auth.signUp(data);
41
42
if (error) {
43
redirect('/error');
44
}
45
46
revalidatePath('/', 'layout');
47
redirect('/');
48
}

5. 在你的登录页面界面中使用服务器操作 #

🌐 5. Use the server actions in your login page UI

1
// app/login/page.tsx
2
3
import { login, signup } from './actions';
4
5
export default function LoginPage() {
6
return (
7
<form>
8
<label htmlFor="email">Email:</label>
9
<input id="email" name="email" type="email" required />
10
<label htmlFor="password">Password:</label>
11
<input id="password" name="password" type="password" required />
12
<button formAction={login}>Log in</button>
13
<button formAction={signup}>Sign up</button>
14
</form>
15
);
16
}

6. 客户端组件 #

🌐 6. Client components

1
'use client';
2
3
// replace this line
4
import { createClientComponentClient } from '@supabase/auth-helpers-nextjs';
5
6
// with
7
import { createClient } from '@/lib/supabase/client';
8
9
export default async function Page() {
10
// replace this line
11
const supabase = createClientComponentClient<Database>();
12
13
// with
14
const supabase = createClient();
15
16
return...
17
}

7. 服务器组件 #

🌐 7. Server components

1
// replace
2
import { cookies } from 'next/headers';
3
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs';
4
5
// with
6
import { createClient } from '@/lib/supabase/server';
7
8
export default async function Page() {
9
// replace
10
const cookieStore = cookies();
11
const supabase = createServerComponentClient<Database>({
12
cookies: () => cookieStore
13
});
14
15
// with
16
const supabase = createClient();
17
18
return...
19
}

8. 路由处理器 #

🌐 8. Route handlers

1
// replace
2
import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs';
3
import { cookies } from 'next/headers';
4
5
// with
6
import { createClient } from '@/lib/supabase/server';
7
8
export async function POST(request: Request) {
9
// replace
10
const supabase = createRouteHandlerClient<Database>({
11
cookies: () => cookieStore,
12
});
13
14
// with
15
const supabase = createClient();
16
17
return...
18
}

同样,你可以用你用 @supabase/ssr 创建的实用函数替换掉用 @supabase/auth-helpers-nextjs 创建的客户端。

🌐 Likewise, you can replace the clients created with @supabase/auth-helpers-nextjs with utility functions you created with @supabase/ssr.

createMiddlewareClientcreateServerClient createClientComponentClientcreateBrowserClient createServerComponentClientcreateServerClient createRouteHandlerClientcreateServerClient

你可以在我们的 SSR 文档中找到更清晰简洁的创建客户端示例 在这里

🌐 You can find more clear and concise examples of creating clients in our SSR documentation.

如果你对本指南有任何反馈,请在下面以评论的形式提供。如果你发现任何问题或对 @supabase/ssr 客户端有反馈,请在 @supabase/ssr 仓库中提交问题。

🌐 If you have any feedback about this guide, provide them as a comment below. If you find any issues or have feedback for the @supabase/ssr client, post them as an issue in @supabase/ssr repo.

像往常一样,我们的 GitHub 社区和 Discord 通道都开放,用于技术讨论和解决你的问题。

🌐 As always, our GitHub community and Discord channel are open for technical discussions and resolving your issues.