Polar
Polar 是一个以开发者为先的支付基础设施。它开箱即用地提供了许多以开发者为先的支付、结账等集成。此插件帮助您将 Polar 与 Better Auth 集成,使您的认证 + 支付流程无缝衔接。
此插件由 Polar 团队维护。对于 bug、问题或功能请求, 请访问 Polar GitHub repo。
功能
- 结账集成
- 客户门户
- 注册时自动创建客户
- 事件摄取和客户计量器,用于灵活的使用量计费
- 使用签名验证安全处理 Polar Webhook
- 引用系统,用于将购买与组织关联
安装
pnpm add better-auth @polar-sh/better-auth @polar-sh/sdk准备工作
转到您的 Polar 组织设置,并创建一个组织访问令牌。将它添加到您的环境变量中。
# .env
POLAR_ACCESS_TOKEN=...配置 BetterAuth 服务端
Polar 插件附带了一些额外的插件,这些插件为您的技术栈添加功能。
- Checkout - 启用无缝的结账集成
- Portal - 使您的客户能够管理他们的订单、订阅和已授予的权益
- Usage - 用于列出客户计量器并摄取事件以进行使用量计费的简单扩展
- Webhooks - 监听相关的 Polar webhook
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,
// 如果您使用 Polar Sandbox 环境,请使用 'sandbox'
// 请记住,访问令牌、产品等在不同环境之间是完全分开的。
// 例如,在生产环境中获取的访问令牌无法在 Sandbox 环境中使用。
server: 'sandbox'
});
const auth = betterAuth({
// ... Better Auth 配置
plugins: [
polar({
client: polarClient,
createCustomerOnSignUp: true,
use: [
checkout({
products: [
{
productId: "123-456-789", // 来自 Polar 仪表板的产品的 ID
slug: "pro" // 用于结账 URL 的自定义 slug,例如 /checkout/pro,便于引用
}
],
successUrl: "/success?checkout_id={CHECKOUT_ID}",
authenticatedUsersOnly: true
}),
portal(),
usage(),
webhooks({
secret: process.env.POLAR_WEBHOOK_SECRET,
onCustomerStateChanged: (payload) => // 当客户相关任何内容更改时触发
onOrderPaid: (payload) => // 当订单支付时触发(购买、订阅续订等)
... // 超过 25 个细粒度的 webhook 处理程序
onPayload: (payload) => // 捕获所有事件的通用处理程序
})
],
})
]
});配置 BetterAuth 客户端
您将使用 BetterAuth 客户端与 Polar 功能交互。
import { createAuthClient } from "better-auth/react";
import { polarClient } from "@polar-sh/better-auth";
// 这就是所有需要的内容
// 所有 Polar 插件等应附加到服务端 BetterAuth 配置中
export const authClient = createAuthClient({
plugins: [polarClient()],
});配置选项
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,
// 如果您使用 Polar Sandbox 环境,请使用 'sandbox'
// 请记住,访问令牌、产品等在不同环境之间是完全分开的。
// 例如,在生产环境中获取的访问令牌无法在 Sandbox 环境中使用。
server: "sandbox",
});
const auth = betterAuth({
// ... Better Auth 配置
plugins: [
polar({
client: polarClient,
createCustomerOnSignUp: true,
getCustomerCreateParams: ({ user }, request) => ({
metadata: {
myCustomProperty: 123,
},
}),
use: [
// 这就是您添加 Polar 插件的地方
],
}),
],
});必需选项
client: Polar SDK 客户端实例
可选选项
createCustomerOnSignUp: 当用户注册时自动创建 Polar 客户getCustomerCreateParams: 自定义函数,用于提供额外的客户创建元数据
客户
启用 createCustomerOnSignUp 时,当 Better-Auth 数据库中添加新用户时,会自动创建新的 Polar 客户。
所有新客户都将与关联的 externalId 创建,该 ID 是您数据库中用户的 ID。这允许我们跳过任何 Polar 到用户数据库的映射。
Checkout 插件
要在您的应用中支持结账,只需将 Checkout 插件传递到 use 属性。
import { polar, checkout } from "@polar-sh/better-auth";
const auth = betterAuth({
// ... Better Auth 配置
plugins: [
polar({
...
use: [
checkout({
// 可选字段 - 将使其可能传递 slug 到结账而不是产品 ID
products: [ { productId: "123-456-789", slug: "pro" } ],
// 结账成功完成后返回的相对 URL
successUrl: "/success?checkout_id={CHECKOUT_ID}",
// 是否允许未经认证的结账会话
authenticatedUsersOnly: true
})
],
})
]
});启用结账后,您可以使用 BetterAuth 客户端上的 checkout 方法初始化 Checkout 会话。这将重定向用户到产品结账页面。
await authClient.checkout({
// 可以在此处传递任何 Polar 产品 ID
products: ["e651f46d-ac20-4f26-b769-ad088b123df2"],
// 或者,如果您在 Checkout 配置中设置了 "products",您可以传递 slug
slug: "pro",
});结账会自动将已认证用户作为客户携带到结账中。电子邮件地址将被“锁定”。
如果 authenticatedUsersOnly 为 false - 则可以触发没有关联客户的结账会话。
组织支持
此插件支持 Organization 插件。如果您将组织 ID 传递到 Checkout 的 referenceId,则可以跟踪组织成员的购买。
const organizationId = (await authClient.organization.list())?.data?.[0]?.id,
await authClient.checkout({
// 可以在此处传递任何 Polar 产品 ID
products: ["e651f46d-ac20-4f26-b769-ad088b123df2"],
// 或者,如果您在 Checkout 配置中设置了 "products",您可以传递 slug
slug: 'pro',
// 参考 ID 将保存为结账、订单和订阅对象的元数据中的 `referenceId`
referenceId: organizationId
});Portal 插件
一个启用客户管理其购买、订单和订阅的插件。
import { polar, checkout, portal } from "@polar-sh/better-auth";
const auth = betterAuth({
// ... Better Auth 配置
plugins: [
polar({
...
use: [
checkout(...),
portal()
],
})
]
});portal 插件为 BetterAuth 客户端提供了一组客户管理方法,这些方法位于 authClient.customer 下。
客户门户管理
以下方法将重定向用户到 Polar 客户门户,在那里他们可以看到订单、购买、订阅、权益等。
await authClient.customer.portal();客户状态
portal 插件还添加了一个便捷的状态方法,用于检索一般的客户状态。
const { data: customerState } = await authClient.customer.state();客户状态对象包含:
- 所有关于客户的数据。
- 他们的活跃订阅列表
- 注意:这不包括由父组织完成的订阅。有关更多信息,请参阅下面的订阅列表方法。
- 他们的已授予权益列表。
- 他们的活跃计量器列表,以及当前余额。
因此,通过该单个对象,您拥有检查是否应提供对您服务的访问所需的所有信息。
您可以在 Polar 文档中了解更多关于 Polar 客户状态的信息。
权益、订单和订阅
portal 插件添加了 3 个便捷方法,用于列出与已认证用户/客户相关的权益、订单和订阅。
所有这些方法都使用 Polar CustomerPortal API
权益
此方法仅列出已认证用户/客户的已授予权益。
const { data: benefits } = await authClient.customer.benefits.list({
query: {
page: 1,
limit: 10,
},
});订单
此方法列出已认证用户/客户的订单,如购买和订阅续订。
const { data: orders } = await authClient.customer.orders.list({
query: {
page: 1,
limit: 10,
productBillingType: "one_time", // 或 'recurring'
},
});订阅
此方法列出与已认证用户/客户关联的订阅。
const { data: subscriptions } = await authClient.customer.subscriptions.list({
query: {
page: 1,
limit: 10,
active: true,
},
});重要 - 组织支持
这不会返回由父组织为已认证用户完成的订阅。
但是,您可以向此方法传递 referenceId。这将返回与该 referenceId 关联的所有订阅,而不是与用户关联的订阅。
因此,为了确定用户是否应有访问权限,请传递用户的组织 ID,以查看该组织是否有活跃订阅。
const organizationId = (await authClient.organization.list())?.data?.[0]?.id,
const { data: subscriptions } = await authClient.customer.orders.list({
query: {
page: 1,
limit: 10,
active: true,
referenceId: organizationId
},
});
const userShouldHaveAccess = subscriptions.some(
sub => // 您的逻辑来检查订阅产品或其他内容。
)Usage 插件
一个用于使用量计费的简单插件。
import { polar, checkout, portal, usage } from "@polar-sh/better-auth";
const auth = betterAuth({
// ... Better Auth 配置
plugins: [
polar({
...
use: [
checkout(...),
portal(),
usage()
],
})
]
});事件摄取
Polar 的使用量计费完全基于事件摄取。从您的应用中摄取事件,创建计量器来表示该使用量,并将计量价格添加到产品中以收取费用。
const { data: ingested } = await authClient.usage.ingest({
event: "file-uploads",
metadata: {
uploadedFiles: 12,
},
});已认证用户会自动与摄取的事件关联。
客户计量器
一个简单的方法,用于列出已认证用户的 Usage 计量器,或我们称之为客户计量器。
客户计量器包含关于他们在您定义的计量器上消费的所有信息。
- 客户信息
- 计量器信息
- 客户计量器信息
- 已消耗单位
- 已计入单位
- 余额
const { data: customerMeters } = await authClient.usage.meters.list({
query: {
page: 1,
limit: 10,
},
});Webhooks 插件
Webhook 插件可用于捕获来自您的 Polar 组织的事件。
import { polar, webhooks } from "@polar-sh/better-auth";
const auth = betterAuth({
// ... Better Auth 配置
plugins: [
polar({
...
use: [
webhooks({
secret: process.env.POLAR_WEBHOOK_SECRET,
onCustomerStateChanged: (payload) => // 当客户相关任何内容更改时触发
onOrderPaid: (payload) => // 当订单支付时触发(购买、订阅续订等)
... // 超过 25 个细粒度的 webhook 处理程序
onPayload: (payload) => // 捕获所有事件的通用处理程序
})
],
})
]
});在您的 Polar 组织设置页面配置 Webhook 端点。Webhook 端点配置在 /polar/webhooks。
将密钥添加到您的环境变量中。
# .env
POLAR_WEBHOOK_SECRET=...该插件支持所有 Polar webhook 事件的处理程序:
onPayload- 任何传入 Webhook 事件的通用处理程序onCheckoutCreated- 当结账创建时触发onCheckoutUpdated- 当结账更新时触发onOrderCreated- 当订单创建时触发onOrderPaid- 当订单支付时触发onOrderRefunded- 当订单退款时触发onRefundCreated- 当退款创建时触发onRefundUpdated- 当退款更新时触发onSubscriptionCreated- 当订阅创建时触发onSubscriptionUpdated- 当订阅更新时触发onSubscriptionActive- 当订阅变为活跃时触发onSubscriptionCanceled- 当订阅取消时触发onSubscriptionRevoked- 当订阅被撤销时触发onSubscriptionUncanceled- 当订阅取消被逆转时触发onProductCreated- 当产品创建时触发onProductUpdated- 当产品更新时触发onOrganizationUpdated- 当组织更新时触发onBenefitCreated- 当权益创建时触发onBenefitUpdated- 当权益更新时触发onBenefitGrantCreated- 当权益授予创建时触发onBenefitGrantUpdated- 当权益授予更新时触发onBenefitGrantRevoked- 当权益授予被撤销时触发onCustomerCreated- 当客户创建时触发onCustomerUpdated- 当客户更新时触发onCustomerDeleted- 当客户删除时触发onCustomerStateChanged- 当客户创建时触发