Better Auth
Plugin de Better Auth para cobros y suscripciones usando Commet
Better Auth es una librería de autenticación moderna para TypeScript. Este plugin integra Commet directamente en tu configuración de better-auth.
Features
- Creación automática del cliente al hacer signup
- Portal del cliente para que tus clientes gestionen sus cobros
- Gestión de suscripciones (get, cancel)
- Control de acceso a features (boolean, metered, seats)
- Registro de uso para cobros metered
- Gestión de licencias para precios por usuario
- Manejo opcional de webhooks con verificación de firma
Instalación
pnpm add better-auth @commet/better-auth @commet/nodenpm install better-auth @commet/better-auth @commet/nodeyarn add better-auth @commet/better-auth @commet/nodebun add better-auth @commet/better-auth @commet/nodePreparación
Obtén tu API key desde el dashboard de Commet. Usa una key de una organización sandbox mientras integras; cambia a una key de organización live cuando pases a producción.
COMMET_API_KEY=ck_...Configuración del servidor
import { betterAuth } from "better-auth";
import {
commet,
portal,
subscriptions,
features,
usage,
seats,
} from "@commet/better-auth";
import { Commet } from "@commet/node";
const commetClient = new Commet({
apiKey: process.env.COMMET_API_KEY,
});
export const auth = betterAuth({
// ... tu config
plugins: [
commet({
client: commetClient,
createCustomerOnSignUp: true,
use: [
portal(),
subscriptions(),
features(),
usage(),
seats(),
],
}),
],
});Configuración del cliente
import { createAuthClient } from "better-auth/react";
import { commetClient } from "@commet/better-auth";
export const authClient = createAuthClient({
plugins: [commetClient()],
});Opciones de configuración
commet({
client: commetClient, // Requerido: instancia del SDK de Commet
createCustomerOnSignUp: true, // Crea automáticamente el cliente al hacer signup
getCustomerCreateParams: ({ user }) => ({
legalName: user.name,
metadata: { source: "web" },
}),
use: [/* plugins */],
})Cuando createCustomerOnSignUp está habilitado, se crea un cliente en Commet automáticamente usando el ID del usuario como customerId. No requiere mapeo de base de datos.
Plugin Portal
Redirige a los usuarios al portal del cliente de Commet para que gestionen sus cobros.
import { commet, portal } from "@commet/better-auth";
commet({
client: commetClient,
use: [
portal({ returnUrl: "/dashboard" }),
],
})// Redirige al portal del cliente de Commet
await authClient.customer.portal();Plugin Subscriptions
Gestiona las suscripciones de los clientes.
import { commet, subscriptions } from "@commet/better-auth";
commet({
client: commetClient,
use: [subscriptions()],
})// Obtener suscripción actual
const { data: subscription } = await authClient.subscription.get();
// Cancelar suscripción
await authClient.subscription.cancel({
subscriptionId: "sub_xxx",
reason: "Muy caro",
immediate: false, // Cancela al cierre del período
});Plugin Features
Verifica el acceso a features para el usuario autenticado.
import { commet, features } from "@commet/better-auth";
commet({
client: commetClient,
use: [features()],
})// Listar todas las features
const { data: featuresList } = await authClient.features.list();
// Obtener una feature específica
const { data: feature } = await authClient.features.get("api_calls");
// Verificar si la feature está habilitada (boolean)
const { data: check } = await authClient.features.check("sso");
// Verificar si el usuario puede consumir una unidad más (metered)
const { data: canUse } = await authClient.features.canUse("api_calls");
// Retorna: { allowed: boolean, willBeCharged: boolean }Plugin Usage
Registra eventos de uso para cobros metered.
import { commet, usage } from "@commet/better-auth";
commet({
client: commetClient,
use: [usage()],
})await authClient.usage.track({
feature: "api_calls",
value: 1,
idempotencyKey: `evt_${Date.now()}`
});El usuario autenticado se asocia automáticamente con el evento.
Plugin Seats
Gestiona licencias por usuario.
import { commet, seats } from "@commet/better-auth";
commet({
client: commetClient,
use: [seats()],
})// Listar todos los balances de licencias
const { data: seatBalances } = await authClient.seats.list();
// Agregar licencias
await authClient.seats.add({ seatType: "member", count: 5 });
// Quitar licencias
await authClient.seats.remove({ seatType: "member", count: 2 });
// Definir cantidad exacta
await authClient.seats.set({ seatType: "admin", count: 3 });
// Definir todos los tipos de licencia a la vez
await authClient.seats.setAll({ admin: 2, member: 10, viewer: 50 });Plugin Webhooks
Maneja los webhooks de Commet. Es opcional, ya que siempre puedes consultar el estado directamente.
import { commet, webhooks } from "@commet/better-auth";
commet({
client: commetClient,
use: [
webhooks({
secret: process.env.COMMET_WEBHOOK_SECRET,
onPayload: (payload) => {
// Handler genérico
},
onSubscriptionCreated: (payload) => {},
onSubscriptionActivated: (payload) => {},
onSubscriptionCanceled: (payload) => {},
onSubscriptionUpdated: (payload) => {},
}),
],
})Configura el endpoint del webhook en tu dashboard de Commet: /api/auth/commet/webhooks
Ejemplo completo
Setup del servidor
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import {
commet as commetPlugin,
portal,
subscriptions,
features,
usage,
seats,
} from "@commet/better-auth";
import { Commet } from "@commet/node";
import { db } from "./db";
import * as schema from "./schema";
const commetClient = new Commet({
apiKey: process.env.COMMET_API_KEY!,
});
export const auth = betterAuth({
database: drizzleAdapter(db, { provider: "pg", schema }),
emailAndPassword: { enabled: true },
plugins: [
commetPlugin({
client: commetClient,
createCustomerOnSignUp: true,
getCustomerCreateParams: ({ user }) => ({
legalName: user.name,
}),
use: [
portal({ returnUrl: "/dashboard" }),
subscriptions(),
features(),
usage(),
seats(),
],
}),
],
});Setup del cliente
import { createAuthClient } from "better-auth/react";
import { commetClient } from "@commet/better-auth";
export const authClient = createAuthClient({
baseURL: process.env.NEXT_PUBLIC_BETTER_AUTH_URL,
plugins: [commetClient()],
});
export const { signIn, signUp, signOut, useSession } = authClient;Uso en componentes
"use client";
import { authClient } from "@/lib/auth-client";
export function BillingSection() {
const handlePortal = async () => {
await authClient.customer.portal();
};
const checkFeature = async () => {
const { data } = await authClient.features.canUse("api_calls");
if (data?.allowed) {
// Continúa con la acción
await authClient.usage.track({ feature: "api_calls" });
}
};
return (
<div>
<button onClick={handlePortal}>Gestionar cobros</button>
<button onClick={checkFeature}>Usar feature</button>
</div>
);
}Relacionado
¿Cómo está esta guía?