😺

「Clerk」で認証して「Supabase」に「そのユーザー」のみがアクセス可能にする

2024/04/16に公開

要件

データベースに「ユーザー自身」だけ「自身のレコード」にアクセスできるようにする

事前知識

Clerkとは?
ログインシステムのSaas

Supabaseとは?
データベースのSaas

それでは、やっていく~!

事前準備

名前「todos」でテーブルを新規作成する。

デフォルトのテーブルに以下を追加する。
Name: title Type: text
Name: user_id Type: text

流れ

やることが多いのでやることをリストアップします。

  1. 必要事項を確認
  2. Supabaseの署名を入手
  3. Supabaseが署名したClerk の JWT token(許可証)を作成
  4. SupabaseでtokenからユーザーIDを抽出するSQL関数の設置
  5. Supabaseでユーザーだけが読み取り可能にする設定
  6. Supabaseでユーザーだけが書き込み可能にする設定
  7. アプリケーションからデータベースへアクセスをテストする

1.必要事項を確認

他人のデータをみれてしまうのはまずいことなのでユーザー自身だけがデータベースのレコードにアクセスできるようにユーザーIDだけでアクセス可能にします。

さらになりすまし防止のために、色々と考慮されているのがJWTを使った方法です。

これだけでセキュリティ対策されているのか心配になりますが公式のやり方なので、これ使っておけばセキュリティ要件は大丈夫のはずです。

必要なこと

  • Supabaseの署名
  • Supabaseが署名したClerk の JWT token(許可証)
  • SupabaseでtokenからユーザーIDを抽出するSQL関数の設置
  • Supabaseでユーザーだけが読み取り可能にする設定
  • Supabaseでユーザーだけが書き込み可能にする設定
  • アプリケーションからデータベースへアクセスをテストする

2. Supabaseの署名を入手

Supabaseのメニューからセッティング

API

ここのボタンを押してコピーする

署名の入手完

3. Supabaseが署名したClerk の JWT token(許可証)を作成

ClerkのメニューからJWT templates

new

supabase

supabaseの署名を貼り付け

保存

これでJWTtokenをアプリケーションで取得可能にする設定が完

4. SupabaseでtokenからユーザーIDを抽出するSQL関数の設置

tokenの中のsubにユーザーIDがデフォルトで保存されているのでSupabaseで抽出するようなSQLの関数をつくります。

https://clerk.com/docs/backend-requests/resources/session-tokens#default-session-claims

SupabaseのメニューからSQLエディタ

new

コピペ

create or replace function requesting_user_id() returns text as $$ select nullif(current_setting('request.jwt.claims', true)::json->>'sub', '')::text; $$ language sql stable;

Runを押す

SQLの関数の設置が完

5. Supabaseでユーザーだけが読み取り可能にする設定

SupabaseのメニューからAuthentication

ポリシー

new

これを選択する

ここに以下を貼り付ける

requesting_user_id() = user_id

ユーザーだけが読み取り可能にする設定完

6. Supabaseでユーザーだけが書き込み可能にする設定

読み取りの書き込み版です。

new

これを選択

trueに上書きする

requesting_user_id() = user_id

ユーザーだけが書き込み可能にする設定完

7. アプリケーションからデータベースへアクセスをテストする

ここにこれを追加する

NEXT_PUBLIC_SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.theithoehto9eihoehyohueouhoeyuh.sGFifSnYEeMbNX_RNDTIsh8PC0BDLGwaOEZMy1iCghs
NEXT_PUBLIC_SUPABASE_URL=https://iuthgiuretiurtuirtge.supabase.co

プロジェクトにパッケージをインストール

npm install @supabase/supabase-js

remixの場合

app\routes\page.tsx
import { json,LoaderFunction } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';
import { getAuth } from "@clerk/remix/ssr.server";
import { createClient } from '@supabase/supabase-js'


export const loader: LoaderFunction = async (args) => {
  const { userId,getToken } = await getAuth(args);
  // トークンを取得
  const token = await getToken({ template: 'supabase' });
  if (!token) {
    throw new Response("Token is missing", { status: 401 });
  }


  const supabase = createClient(process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_KEY!, {
    global: { headers: { Authorization: `Bearer ${token}` } },
  })



  // APIリクエストを送信
  try {

    //書き込み
    const { data } = await supabase.from('todos').insert({ title: "aaa", user_id: userId }).select()
    console.log(data);
    //読み込み
    const { data: todos } = await supabase.from('todos').select('*')
    console.log(todos);
    
    return json(todos);  // jsonヘルパーを使用して適切に返す
  } catch (error) {
    console.error("Failed to fetch data:", error);
    throw new Response('Failed to fetch data', { status: 500 });
  }
};

export default function Hoge() {
  const data = useLoaderData();

  return (
    <div>
      <h1>Resource Data</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

npm run devして/pageにアクセスすると

できた🥳

おわり

認証してデータベースにアクセスするだけなんだけど、暗黙の了解が多くて初心者には大変でした。

JWTの認証はUse Signing algorithm: HS256なのでこれは確認しないとデコードでハマるので気をつけてね。

参考
https://clerk.com/blog/nextjs-supabase-todos-with-multifactor-authentication

Discussion