Vibestacks LogoVibestacks
Authentication

Authentication Configuration

Configure authentication methods, OAuth providers, email verification, and customize behavior for your application.

Vibestacks authentication is highly configurable. Enable or disable sign-in methods, configure OAuth providers, and customize behavior through configuration files.

Configuration File

Authentication settings are defined in the auth configuration:

lib/auth.ts
export const auth = betterAuth({
  // Database connection
  database: drizzleAdapter(db, {
    provider: "pg",
    schema,
  }),

  // Email/password authentication
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: true,
  },

  // Social providers
  socialProviders: {
    google: {
      clientId: env.GOOGLE_CLIENT_ID,
      clientSecret: env.GOOGLE_CLIENT_SECRET,
    },
    // Add more providers here
  },

  // Plugins
  plugins: [
    magicLink({
      sendMagicLink: async ({ email, url }) => {
        // Email sending logic
      },
    }),
    // stripe(), twoFactor(), etc.
  ],
})

Authentication Methods

Email & Password

Enable or disable traditional email/password authentication:

emailAndPassword: {
  enabled: true,  // Set to false to disable
  requireEmailVerification: true,  // Require email confirmation
}

Email Verification

When requireEmailVerification is true, users cannot sign in until they click the verification link sent to their email.

Passwordless authentication via email:

plugins: [
  magicLink({
    sendMagicLink: async ({ email, url }) => {
      await resend.emails.send({
        from: "noreply@yourdomain.com",
        to: email,
        subject: "Sign in to Your App",
        react: MagicLinkEmail({ url }),
      })
    },
  }),
]

To disable magic links, remove the plugin from the configuration.

Two-Factor Authentication

TOTP-based 2FA (optional):

plugins: [
  twoFactor({
    issuer: "Your App Name",  // Shows in authenticator apps
  }),
]

When enabled, users can set up 2FA in their account settings.

OAuth Providers

Google OAuth

  1. Create credentials at Google Cloud Console

  2. Configure redirect URI:

    https://yourdomain.com/api/auth/callback/google

    For local development:

    http://localhost:3000/api/auth/callback/google
  3. Add environment variables:

    .env.local
    GOOGLE_CLIENT_ID=your_client_id
    GOOGLE_CLIENT_SECRET=your_client_secret
  4. Enable in configuration:

    socialProviders: {
      google: {
        clientId: env.GOOGLE_CLIENT_ID,
        clientSecret: env.GOOGLE_CLIENT_SECRET,
      },
    }

GitHub OAuth

  1. Create OAuth app at GitHub Developer Settings

  2. Configure callback URL:

    https://yourdomain.com/api/auth/callback/github
  3. Add environment variables:

    .env.local
    GITHUB_CLIENT_ID=your_client_id
    GITHUB_CLIENT_SECRET=your_client_secret
  4. Enable in configuration:

    socialProviders: {
      github: {
        clientId: env.GITHUB_CLIENT_ID,
        clientSecret: env.GITHUB_CLIENT_SECRET,
      },
    }

Environment Variables

VariableRequiredDescription
BETTER_AUTH_SECRETYesSecret for signing session cookies
DATABASE_URLYesPostgreSQL connection string
NEXT_PUBLIC_SITE_URLYesPublic site URL for email links
RESEND_API_KEYYes*Email delivery (*if email features enabled)
GOOGLE_CLIENT_IDNoGoogle OAuth client ID
GOOGLE_CLIENT_SECRETNoGoogle OAuth client secret
GITHUB_CLIENT_IDNoGitHub OAuth client ID
GITHUB_CLIENT_SECRETNoGitHub OAuth client secret

Generate a secure BETTER_AUTH_SECRET:

openssl rand -base64 32

Keep Secrets Safe

Never commit OAuth secrets or BETTER_AUTH_SECRET to version control. Use environment variables in production.

URL Configuration

Customize authentication page paths:

const authConfig = {
  urls: {
    signIn: "/sign-in",
    signUp: "/sign-up",
    forgotPassword: "/forgot-password",
    resetPassword: "/reset-password",
    callback: "/dashboard",  // Post-auth redirect
  },
}

Email Templates

Authentication emails are React components in the emails/ directory:

emails/
├── magic-link.tsx      # Magic link sign-in
├── verify-email.tsx    # Email verification
└── reset-password.tsx  # Password reset

Customize the templates to match your brand. See Email System for details.

Stripe Integration

Better Auth integrates with Stripe to automatically create customers:

plugins: [
  stripe({
    stripeClient,
    stripeWebhookSecret: env.STRIPE_WEBHOOK_SECRET,
    createCustomerOnSignUp: true,  // Auto-create Stripe customer
  }),
]

When enabled:

  • New users automatically get a Stripe customer ID
  • Customer ID stored in users.stripeCustomerId
  • Enables seamless checkout and subscription management

See Payments System for details.

Protected Routes

Server Components

import { auth } from "@/lib/auth"
import { headers } from "next/headers"
import { redirect } from "next/navigation"

export default async function DashboardPage() {
  const session = await auth.api.getSession({
    headers: await headers(),
  })

  if (!session) {
    redirect("/sign-in")
  }

  return <Dashboard user={session.user} />
}

Client Components

"use client"
import { useSession } from "@/lib/auth-client"
import { useRouter } from "next/navigation"
import { useEffect } from "react"

export function ProtectedComponent() {
  const { data: session, isPending } = useSession()
  const router = useRouter()

  useEffect(() => {
    if (!isPending && !session) {
      router.push("/sign-in")
    }
  }, [session, isPending, router])

  if (isPending) return <Loading />
  if (!session) return null

  return <Content user={session.user} />
}

Middleware (Optional)

For route-level protection:

middleware.ts
import { auth } from "@/lib/auth"
import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"

export async function middleware(request: NextRequest) {
  const session = await auth.api.getSession({
    headers: request.headers,
  })

  if (!session && request.nextUrl.pathname.startsWith("/dashboard")) {
    return NextResponse.redirect(new URL("/sign-in", request.url))
  }

  return NextResponse.next()
}

export const config = {
  matcher: ["/dashboard/:path*"],
}

Common Configurations

Simple email/password authentication:

export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: "pg", schema }),
  emailAndPassword: {
    enabled: true,
    requireEmailVerification: true,
  },
})

Social sign-in only (no passwords):

export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: "pg", schema }),
  emailAndPassword: {
    enabled: false,
  },
  socialProviders: {
    google: {
      clientId: env.GOOGLE_CLIENT_ID,
      clientSecret: env.GOOGLE_CLIENT_SECRET,
    },
  },
})

Next Steps