mcpField
B
better-auth-integration

better-auth-integration

github.com/dodopayments開発13184 回インストール3 週間前に更新
リポジトリ

better-auth-integration について

Better Auth と Dodo Payments を連携し、認証フローに決済機能を組み込むアプリ開発者向けのパッケージです。ユーザーセッションに紐づくチェックアウト、顧客ポータル、サブスクリプション、使用量、署名検証済み Webhook のエンドポイントを提供します。

主な機能

  1. 01登録時の Dodo 顧客同期
  2. 02認証済みチェックアウトと顧客ポータル
  3. 03サブスクリプションと支払い履歴の一覧
  4. 04従量制使用量イベントの送信
  5. 05Webhook 署名の検証と処理

活用シーン

  1. 01ユーザー登録時に Dodo 顧客を作成
  2. 02ログイン中のユーザーによるチェックアウト開始
  3. 03ユーザーへのサブスクリプションと支払いの表示
  4. 04Dodo Webhook の受信と処理

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dodopayments/skills --skill better-auth-integration

インストール後、Claude Code で/better-auth-integrationを入力して読み込まれたか確認します。

詳細

Better Auth との統合

@dodopayments/better-auth を使用して、Better Auth のユーザーを Dodo Payments と同期し、認証済みのチェックアウト、カスタマーポータル、サブスクリプション、支払い、使用量、Webhook のエンドポイントを公開します。

このスキルを使用する場面

  • Better Auth ユーザーのサインアップ時に Dodo の顧客を自動作成する場合。
  • Dodo API キーを公開せずに、サインイン済みユーザーのチェックアウトを開始する場合。
  • ユーザーがカスタマーポータルを開いたり、サブスクリプションや支払いを一覧表示したりできるようにする場合。
  • サインイン済みの顧客の従量課金使用量を送信する場合。
  • Better Auth を通じて、署名検証済みの Dodo Webhook を受信する場合。

インストール

npm install @dodopayments/better-auth dodopayments better-auth zod

Better Auth 1.4 以降の 1.x リリースが必要です。

このパッケージは、小文字のサーバー関数 dodopayments、checkout、portal、usage、webhooks をエクスポートします。クライアントのエントリーポイントは dodopaymentsClient をエクスポートします。

サーバーのセットアップ

各エンドポイントは、use の機能によって登録されます。アプリケーションが呼び出すすべての機能を含めてください。省略すると、そのルートは 404 を返します。

import { betterAuth } from "better-auth";
import DodoPayments from "dodopayments";
import { checkout, dodopayments, portal, usage, webhooks } from "@dodopayments/better-auth";

const dodoPayments = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
  environment: "test_mode",
});

export const auth = betterAuth({
  database: {
    // your database config
  },
  plugins: [
    dodopayments({
      client: dodoPayments,
      createCustomerOnSignUp: true,
      // `user` here is Better Auth's base user: id, name, email, emailVerified,
      // image, createdAt, updatedAt. Anything else (phone number, company, plan)
      // must first be declared via `user.additionalFields` in your Better Auth
      // config, otherwise it does not exist on the type and will be undefined.
      getCustomerParams: (user) => ({
        metadata: { better_auth_user_id: user.id },
      }),
      use: [
        checkout({
          products: [
            { productId: "pdt_premium", slug: "premium-plan" },
          ],
          successUrl: "https://app.example.com/billing/success",
          authenticatedUsersOnly: true,
        }),
        portal(),
        usage(),
        webhooks({
          webhookKey: process.env.DODO_PAYMENTS_WEBHOOK_KEY,
          onPayload: async (payload) => {
            console.log("Verified Dodo webhook:", payload.type);
          },
        }),
      ],
    }),
  ],
});

products はアプリケーションのスラッグを Dodo の商品 ID にマッピングします。authenticatedUsersOnly: true を指定すると、チェックアウトに Better Auth のセッションが必要になります。getCustomerParams は、顧客の同期時にアプリケーションのメタデータを追加します。

このプラグインは、Better Auth の user テーブルに dodoCustomerId フィールドを追加します。プラグインを追加した後、Better Auth CLI でデータベーススキーマを更新します。

npx auth generate   # generate the ORM schema or SQL migration, then apply it yourself
npx auth migrate    # or apply it directly (built-in Kysely adapter only)

ブラウザーのクライアント設定

import { createAuthClient } from "better-auth/react";
import { dodopaymentsClient } from "@dodopayments/better-auth/client";

export const authClient = createAuthClient({
  plugins: [dodopaymentsClient()],
});

これらはブラウザー用のメソッドです。Better Auth のセッション Cookie は自動的に送信されるため、request.headers を渡さないでください。

チェックアウトセッションを作成する

import { authClient } from "@/lib/auth-client";

async function startCheckout() {
  const { data: session, error } = await authClient.dodopayments.checkoutSession({
    slug: "premium-plan",
    referenceId: "order_123",
  });

  if (error) {
    console.error("Checkout error:", error);
    return;
  }

  if (session) {
    window.location.href = session.url;
  }
}

slug は、checkout({ products: [...] }) で設定した商品と一致する必要があります。referenceId は任意の照合用メタデータです。

カスタマーポータルを開く

const { data: portalSession, error } =
  await authClient.dodopayments.customer.portal();

if (error) {
  console.error("Portal error:", error);
} else if (portalSession?.redirect) {
  window.location.href = portalSession.url;
}

ポータルのエンドポイントを使用するには、サインイン済みでメールアドレスが検証済みのユーザーである必要があります。このエンドポイントは、そのユーザーに同期された Dodo の顧客を特定します。

サブスクリプションと支払いを一覧表示する

const { data: subscriptions, error: subscriptionsError } =
  await authClient.dodopayments.customer.subscriptions.list({
    query: { page: 1, limit: 10, status: "active" },
  });

const { data: payments, error: paymentsError } =
  await authClient.dodopayments.customer.payments.list({
    query: { page: 1, limit: 10, status: "succeeded" },
  });

if (subscriptionsError || paymentsError) {
  console.error("Could not load billing history");
} else {
  console.log("Subscriptions:", subscriptions?.items);
  console.log("Payments:", payments?.items);
}

どちらの一覧レスポンスも items エンベロープを使用します。サブスクリプションのフィルターでは page、limit、status を指定できます。支払いのフィルターでは、同じページネーション項目と支払いステータスを使用します。

従量課金の使用量を取り込む

サーバーで usage() を有効にしてから、サインイン済みの顧客のイベントを送信します。

const { data, error } = await authClient.dodopayments.usage.ingest({
  event_id: "evt_usage_123",
  event_name: "api_calls",
  metadata: { requests: 100 },
  timestamp: new Date(),
});

if (error) {
  console.error("Usage ingestion failed:", error);
} else {
  console.log("Ingested events:", data?.ingested_count);
}

usage.ingest と usage.meters.list のどちらも、サインイン済みでメールアドレスが検証済みのユーザーが必要です。このプラグインは、認証済みセッションから customer_id を取得します。event_id はイベントの冪等性キーです。同じイベントを再試行するときは、同じ値を再利用してください。

Webhook エンドポイント

webhooks({ webhookKey, onPayload }) はリクエストを自ら検証して処理します。Better Auth のデフォルトの /api/auth ベースパスを使用する場合は、Dodo ダッシュボードで次の URL を設定します。

https://app.example.com/api/auth/dodopayments/webhooks

2 つ目のルートを作成したり、auth.api.dodopayments.verifyWebhook() を呼び出したりしないでください。このメソッドは存在しません。このプラグインは生のリクエストを読み取り、webhookKey を使用して Standard Webhooks の署名を検証したうえで、onPayload と設定済みのイベント固有コールバックを呼び出します。

登録済みエンドポイント

  • POST /dodopayments/checkout
  • POST /dodopayments/checkout-session
  • GET /dodopayments/customer/portal
  • GET /dodopayments/customer/subscriptions/list
  • GET /dodopayments/customer/payments/list
  • POST /dodopayments/usage/ingest
  • GET /dodopayments/usage/meters/list
  • POST /dodopayments/webhooks

Better Auth は、設定された API ベースパスをこれらのプラグインパスの先頭に付けます。

よくある間違い

portal() だけを有効にする。 use に checkout()、usage()、webhooks() も含めない限り、チェックアウト、利用状況、Webhook のルートは作成されません。

ブラウザー API とサーバー API を混在させる。 ブラウザーコードでは、headers オプションを指定せずに authClient.dodopayments... を呼び出してください。サーバーリクエストを処理する場合は、Better Auth のサーバー API を別途使用してください。

顧客を重複して作成する。 createCustomerOnSignUp が有効な場合、同じユーザーに対して client.customers.create() も呼び出さないでください。

ブラウザーの状態に基づいてアクセス権を付与する。 権利の付与元として、検証済みの Webhook イベント、またはサーバー側からの Dodo への照会を使用してください。

カスタムの Webhook 検証処理を追加する。 /dodopayments/webhooks、署名検証、コールバックの呼び出しは、プラグインが管理します。

リソース

コメント