0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Udemy】Stripe の Webhook からの更新を許可する方法

0
Last updated at Posted at 2025-12-29

はじめに

Supabase の Database Webhooks を使用して、Stripe で発行されたidを Supabaseの profileテーブルのstripe_customerカラムを更新する際に、RLS(Row Level Security)ポリシーによって 更新が拒否される問題 が発生しました。
この記事では、この問題の原因と解決方法を説明します。

開発環境

  • Next.js: 16.1.0
  • React: 19.2.3
  • @supabase/ssr: 0.8.0
  • @supabase/supabase-js: 2.89.0
  • stripe: 20.1.0
  • TypeScript: 5.x

問題の原因

Webhook からのリクエストには認証クッキーが含まれていないため、createServerClient()で作成した Supabase クライアントは認証情報を持ちません。
その結果、RLS ポリシーで auth.uid() を使用した条件が満たされず、更新が拒否されていました。

createServerClient()
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'

export async function createClient() {
  const cookieStore = await cookies()

  return createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
    {
      cookies: {
        getAll() {
          return cookieStore.getAll()
        },
        setAll(cookiesToSet) {
          try {
            cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options))
          } catch {
            // The `setAll` method was called from a Server Component.
            // This can be ignored if you have middleware refreshing
            // user sessions.
          }
        },
      },
    }
  )
}

Webhook と Trigger の違い:

  • Trigger(データベーストリガー)
    データベース内で直接 SQL を実行する機能
  • Webhook
    データベースの変更を外部の API エンドポイント(Next.js の Route Handler など)に通知する機能。データベース外の処理(Stripe 顧客作成など)を実行する際に使用する

問題のあったポリシー

このポリシーでは、認証済みユーザーが自分のレコード(auth.uid() = id)のみ更新可能でした。しかし、Webhook からのリクエストには認証情報がないため、auth.uid()NULL となり、条件を満たさず更新が拒否されていました。

ALTER POLICY "enable_update_profile_customer_id"
ON "public"."profile"
TO authenticated
USING (
  auth.uid() = id
);

解決方法

1. ポリシーの設定

profileテーブルの UPDATE ポリシーを以下のように設定します。

ALTER POLICY "enable_update_profile_customer_id"
ON "public"."profile"
to public
USING (
  auth.uid() IS NULL
  AND
  stripe_customer IS NULL
)
WITH CHECK (
  stripe_customer IS NOT NULL
);

2. ポリシーの動作

  • USING
    auth.uid() IS NULLで認証なし
    更新前の行がstripe_customer IS NULLの場合のみ更新を許可
  • WITH CHECK
    更新後の行がstripe_customer IS NOT NULLであることを確認
  • TO public
    認証の有無に関わらず、条件を満たせばアクセス可能

3. セキュリティ上の利点

  • stripe_customerNULLの時のみ更新可能(初回設定時のみ)
  • 一度設定された値は誤って上書きされることを防止
  • auth.uid() IS NULLにより、Webhook からのリクエストでも動作

さいごに

今回は Webhook を初めて使ったこともあり、問題の特定に時間がかかりました。
また記載した内容で問題は解決しましたが、セキュリティ的にはまだ問題はあると思うので、他に適切な対応方法があれば是非教えてください。

参考サイト

Create a client
Database Webhooks

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?