コンテンツへスキップ
NextAuth.js v4からの移行? こちらの 移行ガイドをご覧ください.

Supabase アダプター

リソース

設定

インストール

npm install @supabase/supabase-js @auth/supabase-adapter

環境変数

SUPABASE_URL
SUPABASE_SERVICE_ROLE_KEY

設定

./auth.ts
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によって公式にメンテナンスまたはサポートされていません。これは、ユーザーとセッションデータを別々のnext_authスキーマに保存するためにSupabase Databaseを使用します。Supabase AuthとインターフェースしないスタンドアロンのAuthサーバーであり、そのため異なる機能セットを提供します。

組み込みメールサーバー電話認証、および多要素認証 (MFA/2FA)などの追加機能を備えた公式にメンテナンスされているAuthサーバーをお探しの場合は、Supabase AuthNext.js用Authヘルパーを使用してください。

スキーマ

メインのスキーマの説明に従ってデータベースを設定し、以下のSQLスキーマをSupabaseの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設定で、「公開されたスキーマ」リストにnext_authを追加することにより、サーバーレスAPIを介してnext_authスキーマを公開します。

ローカルで開発する場合は、Supabase CLIによって生成されたsupabaseフォルダ内のconfig.tomlファイルのschemas配列にnext_authを追加します。

高度な使用方法

行レベルセキュリティ (RLS) の有効化

Postgresは、データへのアクセスを制限するための強力な機能である行レベルセキュリティ (RLS)を提供します。

これは、署名されたJWTをSupabaseサーバーレスAPIに送信することによって機能します。これをNextAuthで動作させるには、2つの手順があります。

セッションコールバックで Supabase の access_token JWT を生成する

JWTに署名するには、jsonwebtokenパッケージを使用します。

npm install jsonwebtoken

セッションコールバックを使用してSupabaseのaccess_tokenを作成し、sessionオブジェクトに追加します。

JWTに署名するには、API設定で確認できるSupabase JWTシークレットを使用します。

./auth.ts
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.dokyumento.jp/reference/core/types#authconfig
export const { handlers, auth, signIn, signOut } = NextAuth({
  // https://authjs.dokyumento.jp/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 でセッションタイプを拡張する

sessionオブジェクトをsupabaseAccessTokenで拡張するには、types/next-auth.d.tsファイルでsessionインターフェースを拡張する必要があります。

types/next-auth.d.ts
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"]
  }
}
Auth.js © Balázs Orbán and Team -2024