mcpField
P
polar-better-auth

polar-better-auth

github.com/tuzzy08开发089 次安装40 周前更新
代码仓库

关于 polar-better-auth

将 Polar 付款和订阅功能接入 Better Auth 的插件,面向构建认证与计费流程的应用开发者。它提供结账、用量计费、客户门户和 Webhook 插件,并支持关联用户或组织。

主要功能

  1. 01注册时自动创建 Polar 客户
  2. 02用户删除时同步删除客户
  3. 03结账与客户门户插件
  4. 04用量事件上报和计量查询
  5. 05接收 Polar Webhook 事件

适用场景

  1. 01为新注册用户创建 Polar 客户
  2. 02在客户端发起产品结账
  3. 03上报用量并查询计量余额
  4. 04按组织订阅检查访问权限

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/tuzzy08/skills --skill polar-better-auth

安装后在 Claude Code 中输入/polar-better-auth确认已加载。

详细介绍

Polar + Better Auth 集成

一个用于将 Polar 付款和订阅集成到身份验证流程中的 Better Auth 插件。

注意: 获取完整文档索引:https://polar.sh/docs/llms.txt

功能

  • 自动创建客户: 将注册用户同步到 Polar 客户。
  • 同步删除: 删除用户时同步删除 Polar 客户。
  • 关联系统: 将购买与组织/用户关联。
  • 插件: 结账、用量(计费)、Webhook 和客户门户。

安装

npm install better-auth @polar-sh/better-auth @polar-sh/sdk
# or
yarn add better-auth @polar-sh/better-auth @polar-sh/sdk
# or
pnpm add better-auth @polar-sh/better-auth @polar-sh/sdk

服务端配置

初始化 Polar 客户端,并将插件添加到 Better Auth 配置中。

环境变量
POLAR_ACCESS_TOKEN=polar_oat_...
POLAR_WEBHOOK_SECRET=...
完整服务端设置
import { betterAuth } from "better-auth";
import {
  polar,
  checkout,
  portal,
  usage,
  webhooks,
} from "@polar-sh/better-auth";
import { Polar } from "@polar-sh/sdk";

const polarClient = new Polar({
  accessToken: process.env.POLAR_ACCESS_TOKEN,
  server: "sandbox", // Use 'sandbox' for testing, defaults to 'production'
});

const auth = betterAuth({
  plugins: [
    polar({
      client: polarClient,
      createCustomerOnSignUp: true, // Auto-create Polar customer
      // Optional: Custom metadata for new customers
      getCustomerCreateParams: ({ user }, request) => ({
        metadata: { source: "better-auth" },
      }),
      use: [
        // 1. Checkout Plugin
        checkout({
          products: [{ productId: "prod_123", slug: "pro" }],
          successUrl: "/success?checkout_id={CHECKOUT_ID}",
          authenticatedUsersOnly: true,
          returnUrl: "https://myapp.com",
          theme: "dark", // 'light' or 'dark'
        }),

        // 2. Customer Portal Plugin
        portal({
          returnUrl: "https://myapp.com",
        }),

        // 3. Usage Billing Plugin
        usage(),

        // 4. Webhooks Plugin
        webhooks({
          secret: process.env.POLAR_WEBHOOK_SECRET,
          onOrderPaid: (payload) => console.log("💸 Order Paid:", payload),
          onCustomerStateChanged: (payload) =>
            console.log("👤 State Changed:", payload),
          onPayload: (payload) => console.log("📨 Other Event:", payload),
        }),
      ],
    }),
  ],
});
服务端选项字典
选项类型描述
clientPolar必需。 Polar SDK 实例。
createCustomerOnSignUpboolean注册时自动创建 Polar 客户。
usePlugin[]子插件数组(结账、门户、用量、Webhook)。
getCustomerCreateParamsFunction返回用于交互的元数据/参数。

客户端配置

import { createAuthClient } from "better-auth/react";
import { polarClient } from "@polar-sh/better-auth";

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

插件摘要

1. 结账插件

支持直接从客户端创建结账会话。

配置:

  • products:{ productId, slug } 数组。支持通过 slug 引用产品。
  • successUrl:付款后的重定向 URL。支持 {CHECKOUT_ID}。
  • authenticatedUsersOnly:true 时要求用户先登录再结账。
  • returnUrl:结账中的返回按钮 URL。
  • theme:light 或 dark。

客户端用法:

await authClient.checkout({
  // Option A: Use slug defined in config
  slug: "pro",
  // Option B: Use direct Product ID
  products: ["prod_123"],
  // Optional: Link to an Organization (B2B)
  referenceId: "org_123",
});
2. 用量插件(计费)

处理用量计费中的事件接收和计量项检索。

客户端用法:

A. 接收事件:

await authClient.usage.ingestion({
  event: "ai_generation", // Must match Meter definition in Dashboard
  metadata: {
    tokens: 156,
    model: "gpt-4",
  },
});

注意:事件会自动关联到已通过身份验证的用户。

B. 列出计量项:

const { data: meters } = await authClient.usage.meters.list({
  query: { page: 1, limit: 10 },
});
// Returns: consumed units, credited units, current balance
3. 门户插件

管理客户对托管式客户门户的访问。

客户端用法:

A. 打开门户:

// Redirects user to Polar Customer Portal
await authClient.customer.portal();

B. 获取客户状态: 返回有效订阅、已授予的权益和计量余额。

const { data: state } = await authClient.customer.state();

C. 列出资源:

// List Active Subscriptions
const { data: subs } = await authClient.customer.subscriptions.list({
  query: { active: true },
});

// List Orders (Purchases)
const { data: orders } = await authClient.customer.orders.list();

// List Benefits
const { data: benefits } = await authClient.customer.benefits.list();
4. Webhook 插件

webhooks 插件会捕获来自 Polar 组织的传入事件。

设置步骤:

  1. 配置端点: 前往 Polar 控制面板 > Webhooks,将端点设置为 /api/auth/polar/webhooks。
  2. 设置密钥: 将 POLAR_WEBHOOK_SECRET 添加到环境变量中。
  3. 添加插件:
import { polar, webhooks } from "@polar-sh/better-auth";

const auth = betterAuth({
  plugins: [
    polar({
      client: polarClient,
      use: [
        webhooks({
          secret: process.env.POLAR_WEBHOOK_SECRET,
          // Handlers
          onCustomerStateChanged: (payload) => {
            console.log("Customer state changed:", payload);
          },
          onOrderPaid: (payload) => {
            console.log("Order paid:", payload);
          },
          // ... over 25+ handlers available
          onPayload: (payload) => {
            console.log("Catch-all event:", payload);
          },
        }),
      ],
    }),
  ],
});

支持的事件:

  • onPayload(捕获所有事件)
  • onCheckoutCreated、onCheckoutUpdated
  • onOrderCreated、onOrderPaid、onOrderRefunded
  • onRefundCreated、onRefundUpdated
  • onSubscriptionCreated、onSubscriptionUpdated
  • onSubscriptionActive、onSubscriptionCanceled、onSubscriptionRevoked
  • onProductCreated、onProductUpdated
  • onCustomerCreated、onCustomerUpdated、onCustomerDeleted、onCustomerStateChanged
  • onBenefitCreated、onBenefitGrantCreated、onBenefitGrantRevoked

常见工作流

同步删除客户

如需在数据库中删除用户时同时删除 Polar 客户:

const auth = betterAuth({
  user: {
    deleteUser: {
      enabled: true,
      afterDelete: async (user) => {
        await polarClient.customers.deleteExternal({
          externalId: user.id,
        });
      },
    },
  },
});
检查组织访问权限

检查用户是否通过组织订阅(B2B)获得访问权限:

const orgId = (await authClient.organization.list())?.data?.[0]?.id;

const { data: orders } = await authClient.customer.orders.list({
  query: {
    active: true,
    referenceId: orgId, // Filter by Org ID
  },
});

const hasAccess = orders.length > 0;

评论

支持 Markdown