UNPKG

@alexasomba/better-auth-paystack

Version:

Production-ready Paystack billing plugin for Better Auth. Supports subscriptions, one-time payments, organization billing, secure webhooks and more

171 lines (130 loc) 4.85 kB
--- name: paystack-tanstack-start description: > Integrate @alexasomba/better-auth-paystack in TanStack Start. Use for Better Auth API routes, tanstackStartCookies(), server functions, getRequestHeaders(), authClient Paystack actions, admin billing server functions, and Cloudflare Workers deployment. type: composition library: "@alexasomba/better-auth-paystack" library_version: "3.1.1" # x-release-please-version license: "MIT" compatibility: "Node.js >=22.0.0; better-auth ^1.6.9; @alexasomba/paystack-node 1.10.x; @alexasomba/better-auth-paystack >=3.0.0 <4.0.0" sources: - "alexasomba/better-auth-paystack:examples/tanstack/README.md" - "alexasomba/better-auth-paystack:examples/tanstack/src/lib/auth.ts" - "alexasomba/better-auth-paystack:examples/tanstack/src/lib/auth-client.ts" - "alexasomba/better-auth-paystack:examples/tanstack/src/routes/api/auth/$.ts" --- ## Setup Create the Better Auth server config with Paystack and `tanstackStartCookies()` last: ```ts import { betterAuth } from "better-auth"; import { tanstackStartCookies } from "better-auth/tanstack-start"; import { paystack } from "@alexasomba/better-auth-paystack"; export const auth = betterAuth({ baseURL: process.env.BETTER_AUTH_URL, plugins: [ paystack({ secretKey: process.env.PAYSTACK_SECRET_KEY!, subscription: { enabled: true, plans: [], }, }), tanstackStartCookies(), ], }); ``` Wire the catch-all auth route: ```ts import { createFileRoute } from "@tanstack/react-router"; import { auth } from "../../../lib/auth"; export const Route = createFileRoute("/api/auth/$")({ server: { handlers: { GET: ({ request }) => auth.handler(request), POST: ({ request }) => auth.handler(request), }, }, }); ``` Create the client plugin: ```ts import { createAuthClient } from "better-auth/client"; import { paystackClient } from "@alexasomba/better-auth-paystack/client"; export const authClient = createAuthClient({ plugins: [paystackClient()], }); ``` ## Core Patterns ### Use Paystack client actions in client components ```tsx import { authClient } from "../lib/auth-client"; export function SubscribeButton() { return ( <button type="button" onClick={async () => { await authClient.subscription.create({ plan: "starter", }); }} > Subscribe </button> ); } ``` Use client actions for checkout and user-triggered subscription lifecycle calls. Do not import server helpers into React components. ### Use server functions for trusted billing operations ```ts import { createServerFn } from "@tanstack/react-start"; import { getRequestHeaders } from "@tanstack/react-start/server"; import { auth } from "./auth"; import { syncPaystackPlans } from "@alexasomba/better-auth-paystack"; export const syncPlans = createServerFn({ method: "POST" }).handler(async () => { const session = await auth.api.getSession({ headers: await getRequestHeaders(), }); if (!session?.user) { throw new Response("Unauthorized", { status: 401 }); } await syncPaystackPlans(await auth.$context, { secretKey: process.env.PAYSTACK_SECRET_KEY!, }); return { ok: true }; }); ``` Pass request headers when Better Auth needs session context. ### Keep SEO and discovery route-owned Use TanStack route `head` functions for titles, descriptions, Open Graph/Twitter tags, canonical links, robots meta, and JSON-LD. Keep `<HeadContent />` in the root document head and `<Scripts />` in the body. Only leaf public pages should emit canonical links. Authenticated dashboards, billing layouts, and Paystack callback routes should be `noindex` and excluded from the sitemap, while still remaining available for checkout redirects and payment verification. ### Keep Cloudflare Worker dependencies compatible The TanStack example deploys to Cloudflare Workers. Keep Better Auth companion packages on compatible versions. If `@better-auth/infra` pulls in `@better-auth/sso`, avoid mixing a beta SSO package with stable `better-auth`. The known safe pin for this package version is: ```yaml overrides: "@better-auth/sso": 1.6.9 ``` ## Common Mistakes ### Putting `tanstackStartCookies()` before Paystack `tanstackStartCookies()` should be last in the Better Auth plugin array so cookie handling wraps the final auth behavior. ### Omitting auth headers in server functions Wrong: ```ts const session = await auth.api.getSession(); ``` Correct: ```ts const session = await auth.api.getSession({ headers: await getRequestHeaders(), }); ``` ### Debugging only root package builds The root package can pass `vp pack` while the example Worker build fails. Reproduce Worker issues with: ```bash pnpm --filter ./examples/tanstack build pnpm --filter ./examples/tanstack exec wrangler deploy --dry-run ```