• ShipSaaSDocumentation
  • Introduction
  • Getting Started
    • Installation
    • Environment Setup
    • Database Setup
    • Development Guide
  • Database
    • Repository Pattern
    • Drizzle Queries
    • Migration Workflow
    • Drizzle Studio
    • Best Practices
  • File Management
    • File Upload Component
    • Server Actions
    • Storage Configuration
  • Authentication Methods
    • Credentials Authentication
    • Magic Link Authentication
    • Two-Factor Authentication (2FA)
    • Social Authentication
    • API Keys & Bearer Tokens
    • Organizations (Multi-tenant)
  • Authorization & Permissions
    • Roles & Hierarchy
    • Route Protection
    • API Protection
    • CASL Permissions
  • Email & Notifications
    • Resend Setup
    • React Email Templates
    • Notification System
    • Email Workflows
    • Customization & Extension
  • Stripe & Payments
    • Stripe Setup
    • Better Auth Integration
    • Checkout Methods
    • Subscription Management
    • Admin Dashboard
    • Webhook Events
  • Architecture & Development
    • Presentation Layer
    • Service Layer
    • Persistence Layer
    • Helpers Architecture
    • Project Structure
    • Development Workflow
  • Testing
    • General Testing
    • Unit Testing
    • UI Component Testing
    • Repository Testing
    • Service Testing
    • End-to-End Testing
  • Deployment
    • Vercel Deployment
    • GitHub Actions CI/CD
    • Database Backup & Restore
    • Database Migrations
    • Troubleshooting Deployment
  • AI Agents Integration
  • Blog Management
    • Blog Setup
    • MDX Blog
    • Database Blog
  • Async Tasks
    • Setup
    • Email Workflows
    • Payment Processing
    • Maintenance Jobs
  1. Documentation
  2. Stripe & Payments
  3. Better Auth Integration
Buydocschangelogsdemocommunity

Better Auth Integration

PreviousStripe SetupNextCheckout Methods
On this page
Better Auth Stripe PluginCore Plugin FeaturesSubscription Lifecycle HooksSubscription CreationSubscription UpdatesSubscription CancellationSubscription DeletionDatabase IntegrationUser-Customer RelationshipPlan ManagementCustom Event ProcessingSecurity FeaturesPlugin BenefitsTesting the Integration

The Better Auth Stripe plugin provides a simple, zero-configuration payment system using external Stripe checkout pages only. This is separate from the Custom Boilerplate's advanced checkout system.

External checkout only: Better Auth uses Stripe-hosted external checkout pages. For embedded forms, guest checkout, or installments, use the Custom Boilerplate System.

Perfect for: Simple SaaS subscriptions where users create accounts before purchasing and you prefer zero configuration over advanced features.

Better Auth Stripe Plugin

The Stripe plugin is configured in src/lib/better-auth/auth.ts and provides automatic integration:

typescript
// From src/lib/better-auth/auth.ts
import { stripe } from '@better-auth/stripe'
import { stripeClient } from '@/lib/stripe/stripe-client'
import { onStripeEvent } from '@/lib/stripe/stripe-events'

plugins: [
  // ... other plugins
  stripe({
    stripeClient,
    stripeWebhookSecret: env.STRIPE_WEBHOOK_SECRET,
    createCustomerOnSignUp: true,
    subscription: {
      enabled: true,
      plans: () => getActivePlansForBetterAuthService(),
      authorizeReference: createAuthorizeReference(),
      // Subscription lifecycle hooks...
    },
    onEvent: onStripeEvent,
  }),
]

Better Auth Stripe Checkout Interface:

Better Auth Stripe integration checkout

Core Plugin Features

Automatic Customer Creation

typescript
// From src/lib/better-auth/auth.ts
stripe({
  createCustomerOnSignUp: true, // Automatically create Stripe customer
  stripeClient,
  stripeWebhookSecret: env.STRIPE_WEBHOOK_SECRET,
})

What happens automatically:

  • User registers → Stripe customer created
  • Customer ID stored in user profile
  • Email synchronization between systems
  • Customer metadata management

Seamless integration: Users don't need to know about Stripe customers - it's all handled automatically during registration.

Dynamic Plan Loading

typescript
// From src/lib/better-auth/auth.ts
subscription: {
  enabled: true,
  plans: () => getActivePlansForBetterAuthService(), // Load plans dynamically
  authorizeReference: createAuthorizeReference(),
}

Features:

  • Plans loaded from your database
  • Dynamic plan updates without code changes
  • Authorization reference for secure access
  • Real-time plan availability

Automatic Event Handling

typescript
// From src/lib/better-auth/auth.ts
stripe({
  onEvent: onStripeEvent, // Custom event handler
  stripeWebhookSecret: env.STRIPE_WEBHOOK_SECRET,
})

Processed automatically:

  • Subscription creation/updates
  • Payment confirmations
  • Invoice status changes
  • Customer updates

Subscription Lifecycle Hooks

The plugin provides hooks for all subscription events with automatic notification integration:

Subscription Creation

typescript
// From src/lib/better-auth/auth.ts
onSubscriptionComplete: async ({ subscription }) => {
  if (!subscription.stripeCustomerId) {
    return
  }

  const user = await getUserByStripeCustomerIdDao(
    subscription.stripeCustomerId as string
  )

  if (user) {
    await createTypedNotificationService({
      userId: user.id,
      type: NotificationTypeConst.subscription_created,
      metadata: { subscription },
    })
  }
}

What happens:

  1. User completes payment
  2. Stripe webhook triggers completion
  3. User receives confirmation email
  4. Database updated with subscription details

Subscription Updates

typescript
// From src/lib/better-auth/auth.ts
onSubscriptionUpdate: async ({ subscription }) => {
  if (!subscription.stripeCustomerId) {
    return
  }

  const user = await getUserByStripeCustomerIdDao(
    subscription.stripeCustomerId as string
  )

  if (user) {
    await createTypedNotificationService({
      userId: user.id,
      type: NotificationTypeConst.subscription_updated,
      metadata: { subscription },
    })
  }
}

Triggers on:

  • Plan upgrades/downgrades
  • Billing cycle changes
  • Seat count modifications
  • Price adjustments

Subscription Cancellation

typescript
// From src/lib/better-auth/auth.ts
onSubscriptionCancel: async ({ subscription }) => {
  if (!subscription.stripeCustomerId) {
    return
  }

  const user = await getUserByStripeCustomerIdDao(
    subscription.stripeCustomerId as string
  )

  if (user) {
    await createTypedNotificationService({
      userId: user.id,
      type: NotificationTypeConst.subscription_canceled,
      metadata: { subscription },
    })
  }
}

Cancellation handling:

  • Immediate cancellation support
  • End-of-period cancellation
  • Reactivation options
  • Access period management

Subscription Deletion

typescript
// From src/lib/better-auth/auth.ts
onSubscriptionDeleted: async ({ subscription }) => {
  if (!subscription.stripeCustomerId) {
    return
  }

  const user = await getUserByStripeCustomerIdDao(
    subscription.stripeCustomerId as string
  )

  if (user) {
    await createTypedNotificationService({
      userId: user.id,
      type: NotificationTypeConst.subscription_deleted,
      metadata: { subscription },
    })
  }
}

Database Integration

The plugin automatically manages subscription data with your database:

User-Customer Relationship

typescript
// From src/db/repositories/user-repository.ts
getUserByStripeCustomerIdDao(stripeCustomerId: string)

Maintains:

  • User ↔ Stripe Customer ID mapping
  • Subscription status synchronization
  • Payment method information
  • Billing address details

Plan Management

typescript
// From src/services/facades/subscription-service-facade.ts
getActivePlansForBetterAuthService()

Provides:

  • Active subscription plans
  • Pricing information
  • Feature limitations
  • Plan availability rules

Custom Event Processing

The plugin delegates custom events to your handler:

typescript
// From src/lib/stripe/stripe-events.ts
export const onStripeEvent = async (event: Stripe.Event) => {
  // Custom business logic for Stripe events
  // Handle events not covered by the plugin
  console.log(`Processing Stripe event: ${event.type}`)

  // Add your custom event handling here
  switch (event.type) {
    case 'invoice.payment_failed':
      // Handle failed payments
      break
    case 'customer.subscription.trial_will_end':
      // Send trial ending notifications
      break
    // Add more custom events...
  }
}

Security Features

Automatic Verification

typescript
// Plugin automatically verifies webhook signatures
stripe({
  stripeWebhookSecret: env.STRIPE_WEBHOOK_SECRET,
})

Security measures:

  • Webhook signature verification
  • Request timestamp validation
  • Duplicate event prevention
  • Secure endpoint protection

Reference Authorization

typescript
// From the plugin configuration
subscription: {
  authorizeReference: createAuthorizeReference(),
}

Controls access to:

  • Subscription management
  • Plan changes
  • Billing information
  • Payment methods

Plugin Benefits

✅

Zero Configuration

Automatic customer creation, webhook processing, and database synchronization

✅

Real-time Updates

Webhooks automatically update subscription status and user access

✅

Email Integration

Automatic email notifications for all subscription lifecycle events

✅

Security Built-in

Webhook verification, authorization checks, and secure data handling

Testing the Integration

1

Verify Plugin Loading

Check your application logs for successful plugin initialization:

[Better Auth] Stripe plugin loaded successfully
[Better Auth] Webhook endpoint: /api/auth/stripe/webhook
2

Test Customer Creation

  1. Register a new user account
  2. Check your Stripe dashboard for the new customer
  3. Verify the customer ID is stored in your database
3

Test Subscription Flow

  1. Complete a test subscription purchase
  2. Check webhook logs for event processing
  3. Verify subscription data in your database
  4. Confirm user received email notification

Better Auth Stripe integration complete! Your authentication system now seamlessly manages Stripe customers and subscriptions with zero additional configuration.