Supabase 适配器
资源
设置
安装
npm install @supabase/supabase-js @auth/supabase-adapter
环境变量
SUPABASE_URL
SUPABASE_SERVICE_ROLE_KEY
配置
import NextAuth from "next-auth"
import { SupabaseAdapter } from "@auth/supabase-adapter"
export const { handlers, auth, signIn, signOut } = NextAuth({
providers: [],
adapter: SupabaseAdapter({
url: process.env.SUPABASE_URL,
secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
}),
})
此适配器由社区开发,并非由 Supabase 官方维护或支持。它使用 Supabase 数据库在单独的 next_auth
架构中存储用户和会话数据。它是一个独立的 Auth 服务器,不与 Supabase Auth 交互,因此提供不同的功能集。
如果您正在寻找具有更多功能(例如 内置电子邮件服务器、电话验证 和 多因素身份验证 (MFA / 2FA))的官方维护的 Auth 服务器,请使用 Supabase Auth 和 Next.js 的 Auth Helpers。
架构
按照我们主 架构 中的描述设置您的数据库,方法是在 Supabase SQL 编辑器 中复制下面的 SQL 架构。
或者,您可以在 SQL 编辑器页面 上选择 NextAuth 快速入门卡,或者 使用 Supabase CLI 创建迁移。
--
-- Name: next_auth; Type: SCHEMA;
--
CREATE SCHEMA next_auth;
GRANT USAGE ON SCHEMA next_auth TO service_role;
GRANT ALL ON SCHEMA next_auth TO postgres;
--
-- Create users table
--
CREATE TABLE IF NOT EXISTS next_auth.users
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
name text,
email text,
"emailVerified" timestamp with time zone,
image text,
CONSTRAINT users_pkey PRIMARY KEY (id),
CONSTRAINT email_unique UNIQUE (email)
);
GRANT ALL ON TABLE next_auth.users TO postgres;
GRANT ALL ON TABLE next_auth.users TO service_role;
--- uid() function to be used in RLS policies
CREATE FUNCTION next_auth.uid() RETURNS uuid
LANGUAGE sql STABLE
AS $$
select
coalesce(
nullif(current_setting('request.jwt.claim.sub', true), ''),
(nullif(current_setting('request.jwt.claims', true), '')::jsonb ->> 'sub')
)::uuid
$$;
--
-- Create sessions table
--
CREATE TABLE IF NOT EXISTS next_auth.sessions
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
expires timestamp with time zone NOT NULL,
"sessionToken" text NOT NULL,
"userId" uuid,
CONSTRAINT sessions_pkey PRIMARY KEY (id),
CONSTRAINT sessionToken_unique UNIQUE ("sessionToken"),
CONSTRAINT "sessions_userId_fkey" FOREIGN KEY ("userId")
REFERENCES next_auth.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE
);
GRANT ALL ON TABLE next_auth.sessions TO postgres;
GRANT ALL ON TABLE next_auth.sessions TO service_role;
--
-- Create accounts table
--
CREATE TABLE IF NOT EXISTS next_auth.accounts
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
type text NOT NULL,
provider text NOT NULL,
"providerAccountId" text NOT NULL,
refresh_token text,
access_token text,
expires_at bigint,
token_type text,
scope text,
id_token text,
session_state text,
oauth_token_secret text,
oauth_token text,
"userId" uuid,
CONSTRAINT accounts_pkey PRIMARY KEY (id),
CONSTRAINT provider_unique UNIQUE (provider, "providerAccountId"),
CONSTRAINT "accounts_userId_fkey" FOREIGN KEY ("userId")
REFERENCES next_auth.users (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE CASCADE
);
GRANT ALL ON TABLE next_auth.accounts TO postgres;
GRANT ALL ON TABLE next_auth.accounts TO service_role;
--
-- Create verification_tokens table
--
CREATE TABLE IF NOT EXISTS next_auth.verification_tokens
(
identifier text,
token text,
expires timestamp with time zone NOT NULL,
CONSTRAINT verification_tokens_pkey PRIMARY KEY (token),
CONSTRAINT token_unique UNIQUE (token),
CONSTRAINT token_identifier_unique UNIQUE (token, identifier)
);
GRANT ALL ON TABLE next_auth.verification_tokens TO postgres;
GRANT ALL ON TABLE next_auth.verification_tokens TO service_role;
在 Supabase 中公开 NextAuth 架构
通过 API 设置 中的无服务器 API 公开 next_auth
架构,方法是将 next_auth
添加到“公开的架构”列表中。
在本地开发时,将 next_auth
添加到 supabase
文件夹中由 Supabase CLI 生成的 config.toml
文件中的 schemas
数组中。
高级用法
启用行级安全 (RLS)
Postgres 提供了一个称为 行级安全 (RLS) 的强大功能,以限制对数据的访问。
这是通过将签名的 JWT 发送到您的 Supabase 无服务器 API 来实现的。让它与 NextAuth 协同工作需要两个步骤。
在会话回调中生成 Supabase access_token
JWT
要签署 JWT,请使用 jsonwebtoken
包。
npm install jsonwebtoken
使用 会话回调 创建 Supabase access_token
并将其附加到 session
对象中。
要签署 JWT,请使用 Supabase JWT 密钥,该密钥可以在 API 设置 中找到。
import NextAuth from "next-auth"
import { SupabaseAdapter } from "@auth/supabase-adapter"
import jwt from "jsonwebtoken"
// For more information on each option (and a full list of options) go to
// https://authjs.oauth.ac.cn/reference/core/types#authconfig
export const { handlers, auth, signIn, signOut } = NextAuth({
// https://authjs.oauth.ac.cn/getting-started/authentication/oauth
providers: [],
adapter: SupabaseAdapter({
url: process.env.NEXT_PUBLIC_SUPABASE_URL,
secret: process.env.SUPABASE_SERVICE_ROLE_KEY,
}),
callbacks: {
async session({ session, user }) {
const signingSecret = process.env.SUPABASE_JWT_SECRET
if (signingSecret) {
const payload = {
aud: "authenticated",
exp: Math.floor(new Date(session.expires).getTime() / 1000),
sub: user.id,
email: user.email,
role: "authenticated",
}
session.supabaseAccessToken = jwt.sign(payload, signingSecret)
}
return session
},
},
})
将 Supabase access_token
JWT 注入客户端
例如,假设以下公共架构
-- Note: This table contains user data. Users should only be able to view and update their own data.
create table users (
-- UUID from next_auth.users
id uuid not null primary key,
name text,
email text,
image text,
constraint "users_id_fkey" foreign key ("id")
references next_auth.users (id) match simple
on update no action
on delete cascade -- if a user is deleted in NextAuth they will also be deleted in our public table.
);
alter table users enable row level security;
create policy "Can view own user data." on users for select using (next_auth.uid() = id);
create policy "Can update own user data." on users for update using (next_auth.uid() = id);
-- This trigger automatically creates a user entry when a new user signs up via NextAuth.
create function public.handle_new_user()
returns trigger as $$
begin
insert into public.users (id, name, email, image)
values (new.id, new.name, new.email, new.image);
return new;
end;
$$ language plpgsql security definer;
create trigger on_auth_user_created
after insert on next_auth.users
for each row execute procedure public.handle_new_user();
现在,supabaseAccessToken
可在 session
对象上使用,并且可以传递给 supabase-js 客户端。这在任何环境中都有效:客户端、服务器端(API 路由、SSR),以及中间件边缘函数!
// Use `useSession()` or `unstable_getServerSession()` to get the NextAuth session.
const { supabaseAccessToken } = session
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
{
global: {
headers: {
Authorization: `Bearer ${supabaseAccessToken}`,
},
},
}
)
// Now you can query with RLS enabled.
const { data, error } = await supabase.from("users").select("*")
TypeScript
您可以将使用 Supabase CLI 生成的类型传递给 Supabase 客户端,以获得增强的类型安全性自动完成。
创建新的 supabase 客户端对象
import { createClient } from "@supabase/supabase-js"
import { Database } from "../database.types"
const supabase = createClient<Database>()
使用 supabaseAccessToken
扩展会话类型
为了使用 supabaseAccessToken
扩展 session
对象,我们需要在 types/next-auth.d.ts
文件中扩展 session
接口
import NextAuth, { type DefaultSession } from "next-auth"
declare module "next-auth" {
// Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
interface Session {
// A JWT which can be used as Authorization header with supabase-js for RLS.
supabaseAccessToken?: string
user: {
// The user's postal address
address: string
} & DefaultSession["user"]
}
}